Skip to content

App Router: non-ASCII dynamic route params crash with ERR_INVALID_CHAR on x-next-cache-tags header #93140

@ornakash

Description

@ornakash

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 next@16.2.2.

Which area(s) are affected?

Dynamic Routes, Headers, Internationalization (i18n), Runtime

Which stage(s) are affected?

next start (local), Vercel (Deployed)

Additional context

  • next@16.2.4 confirmed broken
  • next@16.2.2 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalid linkThe issue was auto-closed due to a missing/invalid reproduction link. A new issue should be opened.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions