[pull] canary from vercel:canary - #1343
Merged
Merged
Conversation
When a client disconnects mid-stream, `pipeNodeReadableToNodeResponse`
destroys the readable React is piping into. React sees its destination
close before the render ended and aborts with a generic `Error("The
destination stream closed early.")`, which `onError` has no way to
distinguish from a real render error, so it ends up in `onRequestError`
as a server render error.
The Web streams path doesn't have this problem: cancelling the readable
passes the `ResponseAborted` reason straight through to React. This does
the same for the Node path by aborting the pipeable with that reason as
soon as the passthrough is destroyed early, before React's own close
handler runs. Genuine render errors still go through untouched.
Fixes #96704
---------
Co-authored-by: Jude Gao <jude.gao@vercel.com>
Reverts #97875 and bumps `sharp` from `^0.35.3` to `^0.35.4`, re-enabling AVIF image optimization. `minimumReleaseAge` interplay (verified with pnpm 10.33.0 and 11.22.0 in a standalone repo with a `file:` dependency declaring sharp as an optional dependency): - sharp 0.35.4 was published on 2026-08-26 and is younger than this repo's 48h `minimumReleaseAge`. - pnpm aborts the whole install with `ERR_PNPM_NO_MATURE_MATCHING_VERSION` when no in-range release satisfies the age gate. This applies to `optionalDependencies` (no warn-and-skip) and through `file:` dependencies alike. - The gate also covers the `@img/sharp-*` binary packages sharp 0.35.4 depends on, so excluding only `sharp@0.35.4` is not enough. - `pnpm-workspace.yaml` therefore exempts `sharp@0.35.4` and `@img/sharp-*` (pnpm does not allow version qualifiers on name patterns in this setting). Both entries can be dropped once 0.35.4 is older than 48 hours. - Downstream users who configure their own `minimumReleaseAge` will hit the same hard install failure when installing a release with this bump until 0.35.4 ages out, unless they add the same excludes. Keeping `^0.35.3` is not a safer alternative: age-gated installs would then silently resolve the vulnerable 0.35.3. Part of https://linear.app/vercel/issue/VOC-34654/ --------- Co-authored-by: Steven <steven@ceriously.com>
- latest resolved to vercel@59.6.2.
- It loads `@vercel/node@8.1.0` -> `@vercel/static-config@3.4.2`.
- `@vercel/static-config` is CommonJS and calls `require("oxc-parser")`.
- `oxc-parser@0.121.0` is ESM-only and requires Node `^20.19.0 ||
>=22.12.0`.
- CI is running Node 20.9.0, which cannot synchronously
- Fixes #82357 - Closes #96985 ### What? `fetchInternalImage()` only rejects the internal response when `statusCode` is falsy, and `MockedResponse` defaults it to `200`, so nothing really gets rejected there. A `307` coming from a `redirects()` entry in `next.config`, or a `404` for a path that isn't there, both count as a successful image fetch. That body then reaches `detectContentType()`, which returns `null`, and all you get is: ``` The requested resource isn't a valid image for /path/to/image.png received null ``` Nothing in that line points back at the response that actually came in, so a redirect looks exactly like a corrupt image. ### Why? `fetchExternalImage()` right above already covers this with `if (!res.ok)` and logs `res.status`. The internal path is the only fetch in the file without that check, so the same failure gets reported at the fetch for remote images, and three steps later as "not a valid image" for local ones. ### How? The guard now rejects anything outside the 2xx range, which is what `res.ok` means, and the log line carries the status next to the href. The thrown `ImageError` message stays generic, same as the external path, so nothing new shows up in the HTTP response body. Because that throw passes `mocked.res.statusCode` into `ImageError`, a non-2xx internal response now reports its own status instead of always landing on `400`. `ImageError` still maps anything under 400 to `500`, so a redirect answers `500` and a `404` stays `404`. That is what `fetchExternalImage()` has always done, and it lines the two up: a missing local image now returns `404` just like a missing remote one. Three assertions in `test/e2e/image-optimizer/util.ts` shift because of that: - `should not forward cookie header`: `/api/conditional-cookie` answers `401` when the cookie is missing, so `400` becomes `401` - `should error if the image file does not exist`: `/does_not_exist.jpg` returns `404` now, with the internal response message - `should error if the resource isn't a valid image`: this one requested `/test.txt`, but the fixture in `public/` is `text.txt`, so it was quietly exercising a missing file instead of a non-image file. Pointed at the file that exists, it keeps its original `400` and finally tests what its name says Two unit tests cover the new guard, one `307` and one `404`. Every other test in that file sets `statusCode = 200`, so they are untouched. #96985 is open against the same report with a different angle: it threads the status through `ImageUpstream` so the existing "isn't a valid image" log can print it. This one stops the request at the fetch, so the redirect never reaches the optimizer at all. Whichever one fits better, feel free to close mine. ### Verification - `jest test/unit/image-optimizer/`: 139/139, and the two new tests fail against a build without the guard - `pnpm test-dev test/e2e/image-optimizer/content-disposition-type.test.ts`: 97/97 - `pnpm test-start test/e2e/image-optimizer/content-disposition-type.test.ts`: 97/97 - `prettier --check` clean on the three changed files <!-- NEXT_JS_LLM --> Co-authored-by: Steven <steven@ceriously.com>
CSRBailout error is the use case for `ReactDOM.browser()`. Replace behind an experimental flag. This PR replaces the bailout error used in next/dynamic ssr: false.
…flag (#96843) Stacked on #96826. This PR replaces the bailout error used by `useSearchParams` with `ReactDOM.browser()` behind the experimental flag. ### How? Move the bailout behind a browser-safe module boundary, use `ReactDOM.browser()` when enabled, and preserve existing behavior otherwise. <!-- NEXT_JS_LLM -->
…lag (#96844) Stacked on #96843. This PR replaces the bailout error used to abort resumed renders with `ReactDOM.browser()` behind the experimental flag. ### How? Pass the flag to the App Router runtime, use `ReactDOM.browser()` as the abort reason when enabled, and preserve existing behavior otherwise. <!-- NEXT_JS_LLM -->
#97936) ### What? `getModuleId()` returns `string | number | null`, and `0` is a valid id. The`ConcatenatedModule` fallback guards it with a truthiness check, so when the concatenated module gets id `0` the client entry is left out of the client reference manifest. ### Why? The [code](https://github.com/vercel/next.js/blob/d09816fdaf2fef7a23751de75a9dde6bb7c2403b/packages/next/src/build/webpack/plugins/flight-manifest-plugin.ts#L516) right above it already checks `modId !== null`. The two checks sit a few lines apart and disagree about whether `0` is a valid id, which looks like an oversight. When it happens the build fails with `Could not find the module ... in the React Client Manifest`, which doesn't point at the cause. Repro: https://github.com/jgruica/next-concat-modid-zero (needs `--webpack` plus `concatenateModules: true`, so it's rare in practice) ### How? One line in `flight-manifest-plugin.ts`: `if (concatenatedModId)` becomes `if (concatenatedModId !== null)`. `null` is still skipped, so nothing elsechanges. Co-authored-by: Marcos Hernanz <96699542+marcoshernanz@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )