From aff86781a4426ef62ac4f541b3cb40d26ef74d0c Mon Sep 17 00:00:00 2001 From: malewis5 Date: Mon, 2 Mar 2026 13:10:40 -0500 Subject: [PATCH] fix(core): render branded page for /404 instead of Vercel default Visiting /404 directly shows the default Vercel black screen because Next.js special-cases this path with a pre-rendered static 404.html, bypassing the [locale] segment entirely. Fix by splitting the layout into a true root layout (app/layout.tsx) owning , , fonts, and globals.css, and converting the locale layout into a nested layout. A new root not-found.tsx renders a minimal branded 404 page for this edge case. Made-with: Cursor --- .changeset/fix-root-not-found.md | 5 +++ core/app/[locale]/layout.tsx | 58 ++++++++++++++------------------ core/app/layout.tsx | 14 ++++++++ core/app/not-found.tsx | 16 +++++++++ 4 files changed, 61 insertions(+), 32 deletions(-) create mode 100644 .changeset/fix-root-not-found.md create mode 100644 core/app/layout.tsx create mode 100644 core/app/not-found.tsx diff --git a/.changeset/fix-root-not-found.md b/.changeset/fix-root-not-found.md new file mode 100644 index 000000000..0fe33621e --- /dev/null +++ b/.changeset/fix-root-not-found.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Add root-level not-found page so /404 renders a branded page instead of the default Vercel error screen diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index f0a08d7f3..11d3d88e8 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -1,6 +1,5 @@ import { Analytics } from '@vercel/analytics/react'; import { SpeedInsights } from '@vercel/speed-insights/next'; -import { clsx } from 'clsx'; import type { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { NextIntlClientProvider } from 'next-intl'; @@ -8,9 +7,6 @@ import { setRequestLocale } from 'next-intl/server'; import { NuqsAdapter } from 'nuqs/adapters/next/app'; import { cache, PropsWithChildren } from 'react'; -import '../../globals.css'; - -import { fonts } from '~/app/fonts'; import { CookieNotifications } from '~/app/notifications'; import { Providers } from '~/app/providers'; import { client } from '~/client'; @@ -140,34 +136,32 @@ export default async function RootLayout({ params, children }: Props) { const privacyPolicyUrl = rootData.data.site.settings?.privacy?.privacyPolicyUrl; return ( - f.variable))} lang={locale}> - - - - - - - {toastNotificationCookieData && ( - - )} - {children} - - - - - - - - - + <> + + + + + + {toastNotificationCookieData && ( + + )} + {children} + + + + + + + + ); } diff --git a/core/app/layout.tsx b/core/app/layout.tsx new file mode 100644 index 000000000..ea754b0fb --- /dev/null +++ b/core/app/layout.tsx @@ -0,0 +1,14 @@ +import { clsx } from 'clsx'; +import { PropsWithChildren } from 'react'; + +import '../globals.css'; + +import { fonts } from '~/app/fonts'; + +export default function RootLayout({ children }: PropsWithChildren) { + return ( + f.variable))} lang="en"> + {children} + + ); +} diff --git a/core/app/not-found.tsx b/core/app/not-found.tsx new file mode 100644 index 000000000..63ff9b6f9 --- /dev/null +++ b/core/app/not-found.tsx @@ -0,0 +1,16 @@ +export default function RootNotFound() { + return ( +
+

Page not found

+

+ The page you are looking for could not be found. +

+ + Go to homepage + +
+ ); +}