vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.99k stars 26.99k forks source link

[PPR] Dynamic route segment params are double encoded #71005

Open steve-marmalade opened 1 month ago

steve-marmalade commented 1 month ago

Link to the code that reproduces this issue

https://github.com/marmalade-labs/ppr-double-encode

To Reproduce

  1. Navigate to https://ppr-double-encode.vercel.app/hello%20world

(note: this bug only shows when deployed to Vercel, not when running locally).

Current vs. Expected behavior

I expected hello%20world to be displayed but instead we see hello%2520world. When running locally or with PPR disabled, it works as expected.

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Fri, 04 Oct 2024 21:51:11 +0000
  Available memory (MB): 62093
  Available CPU cores: 16
Binaries:
  Node: 22.9.0
  npm: 10.8.3
  Yarn: 1.22.22
  pnpm: 9.12.1
Relevant Packages:
  next: 15.0.0-canary.181 // Latest available version is detected (15.0.0-canary.181).
  eslint-config-next: N/A
  react: 19.0.0-rc-2d16326d-20240930
  react-dom: 19.0.0-rc-2d16326d-20240930
  typescript: 5.3.3
Next.js Config:
  output: N/A

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

Partial Prerendering (PPR)

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

Vercel (Deployed)

Additional context

@wyattjoh, @ztanner - thought you might find this one interesting !

steve-marmalade commented 1 month ago

Bizarre, the deployment I linked suddenly stopped reproducing the issue. I can't explain why it's not consistent, but here are the request logs showing it did have this error:

image

Let me know if there's any other debugging info that I can provide

steve-marmalade commented 1 week ago

@wyattjoh , @ztanner - would you be able to give this one a look? I just updated to the latest next canary and am still seeing this on https://ppr-double-encode.vercel.app/hello%20world

Screenshot

image

Vercel logs

image

Code for /app/[slug]/page.tsx

export default async function SlugPage(props: { params: Promise<{ slug: string }> }) {
  const { slug } = await props.params;
  console.log({ slug });
  return (
    <p>{slug}</p>
  )
}