From eeda2bb18d624ee0cff46ec05ec659420b30ac7d Mon Sep 17 00:00:00 2001 From: owen Date: Tue, 23 Jun 2026 20:09:06 -0400 Subject: [PATCH] Fix React hydration crash on invalid route params. Align generateMetadata with page-level notFound() for clan, profile, and PGCR routes so RSC exit status stays consistent. Fixes WEBSITE-4. Co-authored-by: Cursor --- .../profile/[destinyMembershipId]/page.tsx | 7 +------ src/app/clan/[groupId]/page.tsx | 6 ++++-- src/app/clan/server.ts | 11 +---------- src/app/not-found.tsx | 8 ++------ src/app/pgcr/[instanceId]/page.tsx | 13 +++++-------- 5 files changed, 13 insertions(+), 32 deletions(-) diff --git a/src/app/(profile)/profile/[destinyMembershipId]/page.tsx b/src/app/(profile)/profile/[destinyMembershipId]/page.tsx index 3d5ddcea..8f1e4495 100644 --- a/src/app/(profile)/profile/[destinyMembershipId]/page.tsx +++ b/src/app/(profile)/profile/[destinyMembershipId]/page.tsx @@ -113,12 +113,7 @@ export default async function Page({ params }: PageProps) { export async function generateMetadata({ params }: PageProps): Promise { if (!isValidDestinyMembershipId(params.destinyMembershipId)) { - return { - robots: { - follow: true, - index: false - } - } + notFound() } const [profile, basic] = await Promise.all([ diff --git a/src/app/clan/[groupId]/page.tsx b/src/app/clan/[groupId]/page.tsx index b54e4bfa..5cdceaef 100644 --- a/src/app/clan/[groupId]/page.tsx +++ b/src/app/clan/[groupId]/page.tsx @@ -28,12 +28,14 @@ export default async function Page({ params }: PageProps) { export async function generateMetadata({ params }: PageProps): Promise { if (!isValidClanGroupId(params.groupId)) { - return {} + notFound() } const clan = await getClan(params.groupId) - if (!clan) return {} + if (!clan) { + notFound() + } const clanName = fixClanName(clan.detail.name) diff --git a/src/app/clan/server.ts b/src/app/clan/server.ts index 57367021..df9a5b2f 100644 --- a/src/app/clan/server.ts +++ b/src/app/clan/server.ts @@ -1,6 +1,5 @@ import { getClanBannerSource } from "bungie-net-core/endpoints/Destiny2" import { getGroup } from "bungie-net-core/endpoints/GroupV2" -import { notFound } from "next/navigation" import { BungiePlatformError } from "~/models/BungieAPIError" import ServerBungieClient from "~/services/bungie/ServerBungieClient" import { reactRequestDedupe } from "~/util/react-cache" @@ -16,8 +15,6 @@ const clanClient = new ServerBungieClient({ timeout: 6000 }) -const expectedErrorCodes = [1, 7, 621, 622, 686] - export const getClan = reactRequestDedupe(async (groupId: string) => getGroup(clanClient, { groupId }) .then(res => { @@ -26,13 +23,7 @@ export const getClan = reactRequestDedupe(async (groupId: string) => } return res.Response }) - .catch(err => { - if (err instanceof BungiePlatformError && expectedErrorCodes.includes(err.ErrorCode)) { - notFound() - } else { - return null - } - }) + .catch(() => null) ) const bannerClient = new ServerBungieClient({ diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx index 455af0ba..2ee4a7d8 100644 --- a/src/app/not-found.tsx +++ b/src/app/not-found.tsx @@ -1,11 +1,7 @@ -"use client" - -import { PageWrapper } from "~/components/PageWrapper" - export default function NotFound() { return ( - +

{"Not found :("}

- +
) } diff --git a/src/app/pgcr/[instanceId]/page.tsx b/src/app/pgcr/[instanceId]/page.tsx index ab683054..0c88a1ef 100644 --- a/src/app/pgcr/[instanceId]/page.tsx +++ b/src/app/pgcr/[instanceId]/page.tsx @@ -1,4 +1,5 @@ import type { Metadata } from "next" +import { notFound } from "next/navigation" import { PageWrapper } from "~/components/PageWrapper" import PGCR from "~/components/pgcr/pgcr-view" @@ -10,6 +11,7 @@ import { tryPrefetchActivity } from "~/lib/pgcr/server" import { type PGCRPageProps } from "~/lib/pgcr/types" +import { isValidInstanceId } from "~/util/destiny/routeParams" export const revalidate = 0 @@ -24,19 +26,14 @@ export default async function Page({ params }: PGCRPageProps) { } export async function generateMetadata({ params }: PGCRPageProps): Promise { - if (!/^\d+$/.test(params.instanceId)) { - return {} + if (!isValidInstanceId(params.instanceId)) { + notFound() } const activity = await tryPrefetchActivity(params.instanceId) if (!activity) { - return { - robots: { - follow: true, - index: false - } - } + notFound() } const { idTitle, ogTitle, description } = getMetaData(activity)