diff --git a/apps/web/components/error/404-page.tsx b/apps/web/pages/404.tsx
similarity index 97%
rename from apps/web/components/error/404-page.tsx
rename to apps/web/pages/404.tsx
index aa5af61d11..a90e17681f 100644
--- a/apps/web/components/error/404-page.tsx
+++ b/apps/web/pages/404.tsx
@@ -1,5 +1,6 @@
"use client";
+import type { GetStaticPropsContext } from "next";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";
@@ -15,6 +16,8 @@ import { Icon } from "@calcom/ui";
import PageWrapper from "@components/PageWrapper";
+import { getTranslations } from "@server/lib/getTranslations";
+
enum pageType {
ORG = "org",
TEAM = "team",
@@ -244,3 +247,13 @@ export default function Custom404() {
}
Custom404.PageWrapper = PageWrapper;
+
+export const getStaticProps = async (context: GetStaticPropsContext) => {
+ const i18n = await getTranslations(context);
+
+ return {
+ props: {
+ i18n,
+ },
+ };
+};
diff --git a/apps/web/pages/_error.tsx b/apps/web/pages/_error.tsx
index d5e753d1c7..76089811d6 100644
--- a/apps/web/pages/_error.tsx
+++ b/apps/web/pages/_error.tsx
@@ -1,12 +1,115 @@
-import Custom404 from "@components/error/404-page";
+/**
+ * Typescript class based component for custom-error
+ * @link https://nextjs.org/docs/advanced-features/custom-error-page
+ */
+import type { NextPage, NextPageContext } from "next";
+import type { ErrorProps } from "next/error";
+import NextError from "next/error";
+import React from "react";
-const CustomError = () => {
- return ;
+import { getErrorFromUnknown } from "@calcom/lib/errors";
+import { HttpError } from "@calcom/lib/http-error";
+import logger from "@calcom/lib/logger";
+import { redactError } from "@calcom/lib/redactError";
+
+import { ErrorPage } from "@components/error/error-page";
+
+// Adds HttpException to the list of possible error types.
+type AugmentedError = (NonNullable & HttpError) | null;
+type CustomErrorProps = {
+ err?: AugmentedError;
+ message?: string;
+ hasGetInitialPropsRun?: boolean;
+} & Omit;
+
+type AugmentedNextPageContext = Omit & {
+ err: AugmentedError;
+};
+
+const log = logger.getSubLogger({ prefix: ["[error]"] });
+
+const CustomError: NextPage = (props) => {
+ const { statusCode, err, message, hasGetInitialPropsRun } = props;
+
+ if (!hasGetInitialPropsRun && err) {
+ // getInitialProps is not called in case of
+ // https://github.com/vercel/next.js/issues/8592. As a workaround, we pass
+ // err via _app.tsx so it can be captured
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const e = getErrorFromUnknown(err);
+ // can be captured here
+ // e.g. Sentry.captureException(e);
+ }
+ return ;
+};
+
+/**
+ * Partially adapted from the example in
+ * https://github.com/vercel/next.js/tree/canary/examples/with-sentry
+ */
+CustomError.getInitialProps = async (ctx: AugmentedNextPageContext) => {
+ const { res, err, asPath } = ctx;
+ const errorInitialProps = (await NextError.getInitialProps({
+ res,
+ err,
+ } as NextPageContext)) as CustomErrorProps;
+
+ // Workaround for https://github.com/vercel/next.js/issues/8592, mark when
+ // getInitialProps has run
+ errorInitialProps.hasGetInitialPropsRun = true;
+
+ // If a HttpError message, let's override defaults
+ if (err instanceof HttpError) {
+ const redactedError = redactError(err);
+ errorInitialProps.statusCode = err.statusCode;
+ errorInitialProps.title = redactedError.name;
+ errorInitialProps.message = redactedError.message;
+ errorInitialProps.err = {
+ ...redactedError,
+ url: err.url,
+ statusCode: err.statusCode,
+ cause: err.cause,
+ method: err.method,
+ };
+ }
+
+ if (res) {
+ // Running on the server, the response object is available.
+ //
+ // Next.js will pass an err on the server if a page's `getInitialProps`
+ // threw or returned a Promise that rejected
+
+ // Overrides http status code if present in errorInitialProps
+ res.statusCode = errorInitialProps.statusCode;
+
+ log.debug(`server side logged this: ${err?.toString() ?? JSON.stringify(err)}`);
+ log.info("return props, ", errorInitialProps);
+
+ res.setHeader("x-pages-router-error", "true");
+
+ return errorInitialProps;
+ } else {
+ // Running on the client (browser).
+ //
+ // Next.js will provide an err if:
+ //
+ // - a page's `getInitialProps` threw or returned a Promise that rejected
+ // - an exception was thrown somewhere in the React lifecycle (render,
+ // componentDidMount, etc) that was caught by Next.js's React Error
+ // Boundary. Read more about what types of exceptions are caught by Error
+ // Boundaries: https://reactjs.org/docs/error-boundaries.html
+ if (err) {
+ log.info("client side logged this", err);
+ return errorInitialProps;
+ }
+ }
+
+ // If this point is reached, getInitialProps was called without any
+ // information about what the error might be. This is unexpected and may
+ // indicate a bug introduced in Next.js
+ new Error(`_error.tsx getInitialProps missing data at path: ${asPath}`);
+
+ return errorInitialProps;
};
export default CustomError;
-
-// `pages/_error` needs to exist until all routes are
-// fully migrated to App Router. Dynamic routes in Pages Router
-// like `/[user]/[type]` or `/team/[slug]` cannot use App Router's
-// error handling