nextjs - 💡(How to fix) Fix App Router: non-ASCII dynamic route params crash with ERR_INVALID_CHAR on x-next-cache-tags header [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#93140Fetched 2026-04-23 07:21:47
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
0
Author
Timeline (top)
closed ×1commented ×1labeled ×1locked ×1

Error Message

TypeError: Invalid character in header content ["x-next-cache-tags"] at p (.next/server/chunks/ssr/...dist_esm_build_templates_app-page....js) code: 'ERR_INVALID_CHAR'

Root Cause

Root cause: Next.js writes the matched route path into the internal x-next-cache-tags HTTP header (used by the edge cache to index ISR responses by tag). HTTP headers are ASCII-only per RFC 7230, so any byte outside 0x00..0x7F in the path triggers Node's validateHeaderValue. The tag value is not percent-encoded or otherwise sanitized before being written to the header.

Fix Action

Fix / Workaround

Workarounds that do NOT work

  • URL-encoding slugs in generateStaticParams — Next.js decodes and re-tags with the raw non-ASCII form at request time.
  • Middleware NextResponse.rewrite to an ASCII path (including double-encoded and base64url-encoded variants) — the cache tag is built from the original request URL, not the rewritten internal path.
  • Monkey-patching Headers.prototype.set/.append, http.OutgoingMessage.prototype.setHeader, http.ServerResponse.prototype.setHeader, .writeHead, .setHeaders from instrumentation.ts — all patches install but the throw originates from a bundled path in .next/server/chunks/ssr/..._dist_esm_build_templates_app-page_... that bypasses every JS-reachable setter.
  • Patching http.validateHeaderValue — export is a non-configurable getter in the Vercel Node runtime.
  • External caches (CDN / Redis / custom cacheHandler) — the origin response is already a 500; there is nothing valid to cache.

The only workaround found is export const dynamic = 'force-dynamic' on the affected route, which disables ISR entirely.

Code Example

git clone https://github.com/ornakash/nextjs-hebrew-slug-repro
cd nextjs-hebrew-slug-repro
pnpm install
pnpm build
pnpm start

---

curl -I http://localhost:3000/hello   # → 200 OK
curl -I http://localhost:3000/מידע    # → 500 Internal Server Error

---

TypeError: Invalid character in header content ["x-next-cache-tags"]
    at p (.next/server/chunks/ssr/..._dist_esm_build_templates_app-page_....js)
  code: 'ERR_INVALID_CHAR'

---

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Enterprise
Binaries:
  Node: 22.22.0
  npm: 10.9.4
  pnpm: 10.33.0
Relevant Packages:
  next: 16.2.4 // Latest available version is detected (16.2.4).
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.7.3
Next.js Config:
  output: N/A
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/ornakash/nextjs-hebrew-slug-repro

Deployed on Vercel: https://nextjs-hebrew-slug-repro.vercel.app

To Reproduce

git clone https://github.com/ornakash/nextjs-hebrew-slug-repro
cd nextjs-hebrew-slug-repro
pnpm install
pnpm build
pnpm start

Then in another shell:

curl -I http://localhost:3000/hello   # → 200 OK
curl -I http://localhost:3000/מידע    # → 500 Internal Server Error

The Hebrew slug is statically pre-rendered by generateStaticParams. The same 500 occurs when deployed to Vercel.

Current vs. Expected behavior

Current: any dynamic App Router route whose matched params value contains a non-ASCII character (Hebrew, Arabic, Chinese, emoji, ...) responds with 500 on every request. Server log:

TypeError: Invalid character in header content ["x-next-cache-tags"]
    at p (.next/server/chunks/ssr/..._dist_esm_build_templates_app-page_....js)
  code: 'ERR_INVALID_CHAR'

Root cause: Next.js writes the matched route path into the internal x-next-cache-tags HTTP header (used by the edge cache to index ISR responses by tag). HTTP headers are ASCII-only per RFC 7230, so any byte outside 0x00..0x7F in the path triggers Node's validateHeaderValue. The tag value is not percent-encoded or otherwise sanitized before being written to the header.

Expected: Next.js should encodeURI (or similarly ASCII-escape) the tag value before writing x-next-cache-tags, so non-ASCII paths don't crash ISR. Internal tag comparisons already round-trip through a normalized form, so encoding should be compatible with invalidation.

Workarounds that do NOT work

  • URL-encoding slugs in generateStaticParams — Next.js decodes and re-tags with the raw non-ASCII form at request time.
  • Middleware NextResponse.rewrite to an ASCII path (including double-encoded and base64url-encoded variants) — the cache tag is built from the original request URL, not the rewritten internal path.
  • Monkey-patching Headers.prototype.set/.append, http.OutgoingMessage.prototype.setHeader, http.ServerResponse.prototype.setHeader, .writeHead, .setHeaders from instrumentation.ts — all patches install but the throw originates from a bundled path in .next/server/chunks/ssr/..._dist_esm_build_templates_app-page_... that bypasses every JS-reachable setter.
  • Patching http.validateHeaderValue — export is a non-configurable getter in the Vercel Node runtime.
  • External caches (CDN / Redis / custom cacheHandler) — the origin response is already a 500; there is nothing valid to cache.

The only workaround found is export const dynamic = 'force-dynamic' on the affected route, which disables ISR entirely.

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Enterprise
Binaries:
  Node: 22.22.0
  npm: 10.9.4
  pnpm: 10.33.0
Relevant Packages:
  next: 16.2.4 // Latest available version is detected (16.2.4).
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.7.3
Next.js Config:
  output: N/A

Also reproduces on Vercel deployment; also reproduces with [email protected].

Which area(s) are affected?

Dynamic Routes, Headers, Internationalization (i18n), Runtime

Which stage(s) are affected?

next start (local), Vercel (Deployed)

Additional context

  • [email protected] confirmed broken
  • [email protected] confirmed broken
  • Reproduces on both local next start and Vercel production deployment, confirming it's a Next.js bug rather than a Vercel-runtime specific issue.
  • Haven't bisected canary yet; happy to bisect if requested.

extent analysis

TL;DR

The most likely fix is to update Next.js to a version where the issue is resolved or to apply a workaround by setting export const dynamic = 'force-dynamic' on the affected route to disable ISR entirely.

Guidance

  • The issue is caused by Next.js writing non-ASCII characters to the x-next-cache-tags HTTP header, which is not allowed according to RFC 7230.
  • To verify the issue, run the provided reproduction steps and check the server log for the TypeError: Invalid character in header content error.
  • As a temporary workaround, set export const dynamic = 'force-dynamic' on the affected route to disable ISR entirely, which should prevent the 500 Internal Server Error.
  • Consider updating Next.js to a version where the issue is resolved, if available.

Example

No code snippet is provided as the issue is related to the Next.js framework and its handling of non-ASCII characters in HTTP headers.

Notes

The provided workarounds, such as URL-encoding slugs or using middleware to rewrite the path, do not work due to the way Next.js handles cache tags. The only working workaround is to disable ISR entirely on the affected route.

Recommendation

Apply the workaround by setting export const dynamic = 'force-dynamic' on the affected route, as updating to a fixed version of Next.js is not currently available. This workaround disables ISR entirely, which may have performance implications.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING