Skip to content

fix: setRequestLocale before next-intl APIs in all generateMetadata (+ lint rule)#18811

Draft
pettinarip wants to merge 1 commit into
devfrom
fix/setrequestlocale-metadata-systemic
Draft

fix: setRequestLocale before next-intl APIs in all generateMetadata (+ lint rule)#18811
pettinarip wants to merge 1 commit into
devfrom
fix/setrequestlocale-metadata-systemic

Conversation

@pettinarip

Copy link
Copy Markdown
Member

Problem

Every generateMetadata under app/ calls a next-intl API — getTranslations(...) directly and/or the getMetadata / getMdMetadata helpers (which call getTranslations("common") internally) — without first calling setRequestLocale(locale).

next-intl's request config (src/i18n/request.ts) resolves the locale via requestLocale, which reads request headers unless setRequestLocale has primed the per-request cache. So any generateMetadata that runs a next-intl API before setRequestLocale opts the route into dynamic rendering and, for params rendered on-demand (invalid-locale / unknown-slug bot probes not covered by generateStaticParams), Next.js throws:

Error: Page changed from static to dynamic at runtime /..., reason: headers
    at get requestLocale (next-intl)

Prerendered locales are built with no headers, so they were unaffected — which is why only a handful of routes actually alerted in production while the gap was latent across ~54 pages.

Why not a central fix?

There's no single choke point: getMetadata receives locale but calls getTranslations("common") (locale-less), and pages also call getTranslations("page-x") directly before getMetadata to build the title. Fixing only the helper leaves the direct call reading headers. setRequestLocale(locale) at the top of each generateMetadata neutralizes both paths at once, which is the pattern next-intl documents for static rendering.

Changes

  • Add setRequestLocale(locale) at the top of every generateMetadata in app/ that uses a next-intl API (before the first next-intl call).
  • Add a local ESLint rule local-rules/require-setrequestlocale (error on app/**) via eslint-plugin-local-rules. It flags any generateMetadata that calls a next-intl API (getTranslations, getMessages, getMetadata, getMdMetadata, …) before setRequestLocale, so this can't regress.

Verification

  • pnpm type-check
  • pnpm lint (full repo) ✅ — 0 errors
  • ESLint rule unit-tested with RuleTester (valid: correct order / no-intl / non-generateMetadata; invalid: missing / wrong-order / helper-only) and confirmed firing on a scratch page.

Relationship to the recovery PRs

Overlaps recovery PRs #18785, #18797, #18798, #18800 on those 4 files (identical one-line addition in generateMetadata). Whichever merges first, reconciliation is trivial. Note: this PR intentionally scopes to generateMetadata only — the page-body ordering fixes for wallets/videos live in those recovery PRs.

🤖 Generated with Claude Code

… lint rule

Every `generateMetadata` in app/ called a next-intl API (getTranslations
directly and/or via the getMetadata/getMdMetadata helpers) without first
calling `setRequestLocale(locale)`. Without it, next-intl reads the locale
from request headers, opting the route into dynamic rendering and throwing
"Page changed from static to dynamic at runtime, reason: headers" for
on-demand params (invalid-locale/unknown-slug bot probes not covered by
generateStaticParams).

Prerendered locales were unaffected (built with no headers), so only a few
routes alerted in prod, but the gap was latent across ~54 pages.

- Add `setRequestLocale(locale)` at the top of every generateMetadata that
  uses a next-intl API.
- Add a local ESLint rule (local-rules/require-setrequestlocale, error on
  app/**) that flags any generateMetadata calling a next-intl API before
  setRequestLocale, so this can't regress.

Overlaps recovery PRs #18785 #18797 #18798 #18800 on those 4 files (same
one-line addition); trivial to reconcile whichever merges first.
@netlify

netlify Bot commented Jul 15, 2026

Copy link
Copy Markdown

Deploy Preview for ethereumorg ready!

Name Link
🔨 Latest commit bb1f64d
🔍 Latest deploy log https://app.netlify.com/projects/ethereumorg/deploys/6a57bb20e2af9200083237ab
😎 Deploy Preview https://deploy-preview-18811.ethereum.it
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
7 paths audited
Performance: 61 (🟢 up 5 from production)
Accessibility: 95 (no change from production)
Best Practices: 100 (no change from production)
SEO: 98 (no change from production)
PWA: 59 (🔴 down 1 from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added config ⚙️ Changes to configuration files dependencies 📦 Changes related to project dependencies labels Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config ⚙️ Changes to configuration files dependencies 📦 Changes related to project dependencies

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant