Link to the code that reproduces this issue
https://github.com/agurtovoy/nextjs-incomplete-link-bug
To Reproduce
- Deploy the repo above to Vercel
- Open the deployed site, get
Application error: a client-side exception has occurred (see the browser console for more information). (sample deployment)
Current vs. Expected behavior
Current: passing incomplete/invalid URL to next/link throws an exception on render (in production) even if the user never clicks on the link.
Expected: providing incomplete/invalid URL to next/link should never lead to an exception during rendering.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 23.5.0: Wed May 1 20:12:58 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6000
Available memory (MB): 16384
Available CPU cores: 10
Binaries:
Node: 18.20.3
npm: 10.7.0
Yarn: 1.22.21
pnpm: 7.26.3
Relevant Packages:
next: 14.2.3 // Latest available version is detected (14.2.3).
eslint-config-next: 14.2.3
react: 18.3.1
react-dom: 18.3.1
typescript: 5.4.5
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Navigation, Runtime
Which stage(s) are affected? (Select all that apply)
Vercel (Deployed), Other (Deployed)
Additional context
The offending exception is thrown by the URL constructor here (while preparing to prefetch the URL):
|
const url = new URL(addBasePath(href), window.location.href) |
While the URL constructor is pretty tolerant and in most cases will obediently return some sort of URL, even if you pass it arguably nonsensical args, it does throw in a couple of circumstances. One of these circumstances is an attempt to mix protocols, e.g.: new URL('http:', 'https://vercel.com').
That means something as innocent as <Link href="http:">Home</Link> will currently throw on render in production.
Note that because prefetching is unconditionally disabled in dev, it's easy to ship a broken site w/o knowing it.
Also note that there is other prefetching code elsewhere in the codebase (e.g. page router) where the assumption seems to be that the URL constructor doesn't throw.
Link to the code that reproduces this issue
https://github.com/agurtovoy/nextjs-incomplete-link-bug
To Reproduce
Application error: a client-side exception has occurred (see the browser console for more information).(sample deployment)Current vs. Expected behavior
Current: passing incomplete/invalid URL to
next/linkthrows an exception on render (in production) even if the user never clicks on the link.Expected: providing incomplete/invalid URL to
next/linkshould never lead to an exception during rendering.Provide environment information
Operating System: Platform: darwin Arch: arm64 Version: Darwin Kernel Version 23.5.0: Wed May 1 20:12:58 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6000 Available memory (MB): 16384 Available CPU cores: 10 Binaries: Node: 18.20.3 npm: 10.7.0 Yarn: 1.22.21 pnpm: 7.26.3 Relevant Packages: next: 14.2.3 // Latest available version is detected (14.2.3). eslint-config-next: 14.2.3 react: 18.3.1 react-dom: 18.3.1 typescript: 5.4.5 Next.js Config: output: N/AWhich area(s) are affected? (Select all that apply)
Navigation, Runtime
Which stage(s) are affected? (Select all that apply)
Vercel (Deployed), Other (Deployed)
Additional context
The offending exception is thrown by the
URLconstructor here (while preparing to prefetch the URL):next.js/packages/next/src/client/components/app-router.tsx
Line 372 in 004651b
While the
URLconstructor is pretty tolerant and in most cases will obediently return some sort of URL, even if you pass it arguably nonsensical args, it does throw in a couple of circumstances. One of these circumstances is an attempt to mix protocols, e.g.:new URL('http:', 'https://vercel.com').That means something as innocent as
<Link href="http:">Home</Link>will currently throw on render in production.Note that because prefetching is unconditionally disabled in dev, it's easy to ship a broken site w/o knowing it.
Also note that there is other prefetching code elsewhere in the codebase (e.g. page router) where the assumption seems to be that the
URLconstructor doesn't throw.