vercel/next.js · error · DecodeError

Failed to decode path param(s).

Error message

Failed to decode path param(s).

What it means

Thrown by decodePathParams (as a DecodeError) when a path segment contains malformed percent-encoding that decodeURIComponent cannot parse (e.g. '%zz' or a lone '%' at the end). Next.js decodes URL path params to match dynamic routes, and invalid escapes make decoding impossible.

Source

Thrown at packages/next/src/server/lib/router-utils/decode-path-params.ts:21

/**
 * We only encode path delimiters for path segments from
 * getStaticPaths so we need to attempt decoding the URL
 * to match against and only escape the path delimiters
 * this allows non-ascii values to be handled e.g.
 * Japanese characters.
 * */
function decodePathParams(pathname: string): string {
  // TODO: investigate adding this handling for non-SSG
  // pages so non-ascii names also work there.
  return pathname
    .split('/')
    .map((seg) => {
      try {
        seg = escapePathDelimiters(decodeURIComponent(seg), true)
      } catch (_) {
        // An improperly encoded URL was provided
        throw new DecodeError('Failed to decode path param(s).')
      }
      return seg
    })
    .join('/')
}

export { decodePathParams }

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Ensure the client sends properly percent-encoded URLs (e.g. %20 for space, %25 for a literal %).
  2. If a proxy is double-encoding, fix the proxy to pass the raw path through.
  3. Add a rewrite or middleware to sanitize/normalize incoming paths before they reach the router.
  4. For genuinely malformed requests, expect a 400 and ensure your error page handles it gracefully.

Example fix

// before: client sends a raw percent
// GET /files/report%.pdf  -> throws DecodeError

// after: client encodes the percent
// GET /files/report%25.pdf
Defensive patterns

Strategy: try-catch

Validate before calling

function isDecodablePath(pathname: string): boolean {
  return pathname.split('/').every(seg => {
    try { decodeURIComponent(seg); return true } catch { return false }
  })
}

Type guard

function isDecodablePath(pathname: string): boolean {
  try { decodeURIComponent(pathname); return true } catch { return false }
}

Try / catch

try {
  decodePathParams(pathname)
} catch (e) {
  if (e instanceof DecodeError) return new Response('Bad Request', { status: 400 })
  throw e
}

Prevention

When it happens

Trigger: A request URL contains a path segment with an invalid percent-escape sequence, such as /post/%zz or /user/100%. decodeURIComponent throws URIError which is rethrown as DecodeError.

Common situations: Clients sending unencoded special characters, a reverse proxy double-decoding/encoding, or a misconfigured redirect that mangles the path. Bots/scanners hitting odd URLs also trigger this.

Understand the failure class

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/bc316d32fe9d3570. Report an issue: GitHub.