vercel / vercel/next.js

Nextjs ResponseCookies function crashes with unhandled exception on decodeURIComponent if cookies has any string with % on it.

Open
#70,523 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug Middleware Runtime
Dominant language
JavaScript
Stars
142k
Forks
32.5k
Avg merge
2d 14h
Merged PRs (30d)
351

Description

Link to the code that reproduces this issue

https://github.com/Sathosk/reponse-cookies-issue-reproduction-app

To Reproduce
  1. Run npm run dev
  2. Open localhost:3000
Current vs. Expected behavior

The application should handle the situation gracefully and not crash.

Instead, the following error occurs:

 ⨯ URIError: URI malformed
    at decodeURIComponent (<anonymous>)
    at Home (./src/app/page.tsx:11:78)
    at AsyncLocalStorage.run (node:async_hooks:346:14)
    at stringify (<anonymous>)
    at AsyncResource.runInAsyncScope (node:async_hooks:206:9)
digest: "2977456002"
Provide environment information
Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 10 Pro
  Available memory (MB): 16333
  Available CPU cores: 12
Binaries:
  Node: 20.14.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 15.0.0-canary.171 // Latest available version is detected (15.0.0-canary.171).
  eslint-config-next: N/A
  react: 19.0.0-rc-778e1ed2-20240926
  react-dom: 19.0.0-rc-778e1ed2-20240926
  typescript: 5.3.3
Next.js Config:
  output: N/A
Which area(s) are affected? (Select all that apply)

Middleware, Runtime

Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local), next start (local), Other (Deployed)

Additional context

The issue seems to stem from the ResponseCookies function that Next.js provides for creating a new Set-Cookie header.

Before version 14.2.8, cookies set in middleware could not be synced with RSC due to the request-response cycle. To bypass this issue, I implemented a custom function:

function applySetCookie(req: NextRequest, res: NextResponse): void {
    // parse the outgoing Set-Cookie header
    const setCookieHeader = res.headers.getSetCookie()
    const parsedCookies = parseSetCookies(setCookieHeader) // This used to be ResponseCookies function provided by Nextjs

    // Build a new Cookie header for the request by adding the setCookies
    const newReqHeaders = new Headers(req.headers)
    const newReqCookies = new RequestCookies(newReqHeaders)
    parsedCookies.forEach((cookie) => {
      newReqCookies.set(cookie)
    })
    // set “request header overrides” on the outgoing response
    NextResponse.next({
      request: { headers: newReqHeaders },
    }).headers.forEach((value, key) => {
      if (
        key === 'x-middleware-override-headers' ||
        key.startsWith('x-middleware-request-')
      ) {
        res.headers.set(key, value)
      }
    })
}

This approach worked, but I faced the same issue whenever a cookie contained a % character. It's not uncommon for cookies to have such characters.

The core issue here is that ResponseCookies is not handling exceptions thrown by the decodeURIComponent function. My workaround was to write a custom parser for handling cookies, and I have not faced any problems since.

However, starting with version 14.2.8, the functionality of merging cookies from middleware was added in the source code, essentially doing what I was doing. But the problem persists with the use of ResponseCookies, which crashes the application when decodeURIComponent throws an exception.

While I can implement a fix on my end, I believe this issue should be handled by the framework to prevent similar crashes.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the linked reproduction with npm run dev and inspect src/app/page.tsx at the reported decodeURIComponent call. Trace the ResponseCookies path used by middleware cookie merging, then add coverage for a cookie containing an invalid percent sequence. Done means the application handles that cookie without an unhandled URIError.

Written by the indexing model from the issue text.

Assessment

Tech stack
next.js, typescript
Domain
backend, web-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
57/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.