From 3178712b7eeaa1fd91378ca188762d8a6df6a651 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 11:17:18 +0200 Subject: [PATCH 1/3] fix(seo): wrap dev-tools category generatemetadata in try/catch to avoid 502 cascade --- .../developers/tools/[category]/page.tsx | 40 +++++++++++++------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/app/[locale]/developers/tools/[category]/page.tsx b/app/[locale]/developers/tools/[category]/page.tsx index 6b662021e7b..d9dc0fe4adf 100644 --- a/app/[locale]/developers/tools/[category]/page.tsx +++ b/app/[locale]/developers/tools/[category]/page.tsx @@ -11,6 +11,8 @@ import { Section } from "@/components/ui/section" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" +import { DEFAULT_LOCALE } from "@/lib/constants" + import CategoryToolsGrid from "../_components/CategoryToolsGrid" import HighlightsSection from "../_components/HighlightsSection" import ToolModalContents from "../_components/ToolModalContents" @@ -152,20 +154,32 @@ export async function generateMetadata(props: { const params = await props.params const { locale, category } = params - if (!VALID_CATEGORY_SLUGS.has(category as DeveloperToolCategorySlug)) { - notFound() + try { + if (!VALID_CATEGORY_SLUGS.has(category as DeveloperToolCategorySlug)) { + throw new Error(`Invalid developer tools category: ${category}`) + } + + const t = await getTranslations("page-developers-tools") + + return await getMetadata({ + locale, + slug: ["developers", "tools", category], + title: t(`page-developers-tools-category-${category}-title`), + description: t( + `page-developers-tools-category-${category}-meta-description` + ), + }) + } catch { + const t = await getTranslations({ + locale: DEFAULT_LOCALE, + namespace: "common", + }) + + return { + title: t("page-not-found"), + description: t("page-not-found-description"), + } } - - const t = await getTranslations("page-developers-tools") - - return await getMetadata({ - locale, - slug: ["developers", "tools", category], - title: t(`page-developers-tools-category-${category}-title`), - description: t( - `page-developers-tools-category-${category}-meta-description` - ), - }) } export default Page From e1e90d12d3a5dc969cb3add21f6d3fc6ed95e7b0 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Tue, 21 Apr 2026 11:22:05 +0200 Subject: [PATCH 2/3] fix(seo): wrap apps categories generatemetadata in try/catch to avoid 502 cascade --- .../apps/categories/[catetgoryName]/page.tsx | 59 ++++++++++++------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/app/[locale]/apps/categories/[catetgoryName]/page.tsx b/app/[locale]/apps/categories/[catetgoryName]/page.tsx index b3f72ad03b8..5fe2eeb5cc8 100644 --- a/app/[locale]/apps/categories/[catetgoryName]/page.tsx +++ b/app/[locale]/apps/categories/[catetgoryName]/page.tsx @@ -36,6 +36,8 @@ import { slugify } from "@/lib/utils/url" import { appsCategories } from "@/data/apps/categories" +import { DEFAULT_LOCALE } from "@/lib/constants" + import AppsHighlight from "../../_components/AppsHighlight" import AppsTable from "../../_components/AppsTable" import SuggestAnApp from "../../_components/SuggestAnApp" @@ -223,35 +225,48 @@ export async function generateMetadata(props: { }) { const params = await props.params const { locale, catetgoryName } = params - const t = await getTranslations("page-apps") - // Normalize slug to lowercase - const normalizedSlug = catetgoryName.toLowerCase() + try { + const t = await getTranslations("page-apps") - // Find category by matching the slug - const categoryEntry = Object.entries(appsCategories).find( - ([, categoryData]) => categoryData.slug === normalizedSlug - ) + // Normalize slug to lowercase + const normalizedSlug = catetgoryName.toLowerCase() - if (!categoryEntry) { - notFound() - } + // Find category by matching the slug + const categoryEntry = Object.entries(appsCategories).find( + ([, categoryData]) => categoryData.slug === normalizedSlug + ) - const [categoryEnum, category] = categoryEntry + if (!categoryEntry) { + throw new Error(`App category not found: ${catetgoryName}`) + } - if (!isValidCategory(categoryEnum)) { - notFound() - } + const [categoryEnum, category] = categoryEntry - const title = t(category.metaTitle) - const description = t(category.metaDescription) + if (!isValidCategory(categoryEnum)) { + throw new Error(`Invalid app category enum: ${categoryEnum}`) + } - return await getMetadata({ - locale, - slug: ["apps", "categories", normalizedSlug], - title, - description, - }) + const title = t(category.metaTitle) + const description = t(category.metaDescription) + + return await getMetadata({ + locale, + slug: ["apps", "categories", normalizedSlug], + title, + description, + }) + } catch { + const t = await getTranslations({ + locale: DEFAULT_LOCALE, + namespace: "common", + }) + + return { + title: t("page-not-found"), + description: t("page-not-found-description"), + } + } } export default Page From 46629213dca893c6f7b78463a3bf3415e4a2712c Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Thu, 23 Apr 2026 15:57:55 +0200 Subject: [PATCH 3/3] fix(seo): preserve request locale in generateMetadata fallbacks Drop the explicit `locale: DEFAULT_LOCALE` in the try/catch fallbacks: next-intl's `getRequestConfig` builds the messages map once per request from `requestLocale`, so passing an explicit locale to `getTranslations` only changes the formatting locale, not which strings are returned. The fallback was already rendering the request locale's strings -- this makes the code honest about that and preserves the user's language for the `page-not-found` copy. --- app/[locale]/apps/categories/[catetgoryName]/page.tsx | 11 +++-------- app/[locale]/developers/tools/[category]/page.tsx | 9 ++------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/app/[locale]/apps/categories/[catetgoryName]/page.tsx b/app/[locale]/apps/categories/[catetgoryName]/page.tsx index 5fe2eeb5cc8..d45c67eae6f 100644 --- a/app/[locale]/apps/categories/[catetgoryName]/page.tsx +++ b/app/[locale]/apps/categories/[catetgoryName]/page.tsx @@ -36,8 +36,6 @@ import { slugify } from "@/lib/utils/url" import { appsCategories } from "@/data/apps/categories" -import { DEFAULT_LOCALE } from "@/lib/constants" - import AppsHighlight from "../../_components/AppsHighlight" import AppsTable from "../../_components/AppsTable" import SuggestAnApp from "../../_components/SuggestAnApp" @@ -151,7 +149,7 @@ const Page = async (props: { Ethereum.org - + / @@ -159,7 +157,7 @@ const Page = async (props: { {t("page-apps-all-apps")} - + / @@ -257,10 +255,7 @@ export async function generateMetadata(props: { description, }) } catch { - const t = await getTranslations({ - locale: DEFAULT_LOCALE, - namespace: "common", - }) + const t = await getTranslations("common") return { title: t("page-not-found"), diff --git a/app/[locale]/developers/tools/[category]/page.tsx b/app/[locale]/developers/tools/[category]/page.tsx index d9dc0fe4adf..2f023144784 100644 --- a/app/[locale]/developers/tools/[category]/page.tsx +++ b/app/[locale]/developers/tools/[category]/page.tsx @@ -11,8 +11,6 @@ import { Section } from "@/components/ui/section" import { getAppPageContributorInfo } from "@/lib/utils/contributors" import { getMetadata } from "@/lib/utils/metadata" -import { DEFAULT_LOCALE } from "@/lib/constants" - import CategoryToolsGrid from "../_components/CategoryToolsGrid" import HighlightsSection from "../_components/HighlightsSection" import ToolModalContents from "../_components/ToolModalContents" @@ -119,7 +117,7 @@ const Page = async (props: {

{t("page-developers-tools-categories-title-other")}

-
+
{DEV_TOOL_CATEGORIES.filter(({ slug }) => slug !== category).map( ({ slug, Icon }) => (