Skip to content

[pull] canary from vercel:canary#1045

Merged
pull[bot] merged 12 commits into
code:canaryfrom
vercel:canary
May 13, 2026
Merged

[pull] canary from vercel:canary#1045
pull[bot] merged 12 commits into
code:canaryfrom
vercel:canary

Conversation

@pull

@pull pull Bot commented May 13, 2026

Copy link
Copy Markdown

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 : )

gaojude and others added 8 commits May 13, 2026 04:06
The "AI agent hint" comment on the docs landing page (`docs/index.mdx`)
tells every agent reading the docs on every task to export
`unstable_instant` to fix slow client-side navigations.

That's too aggressive for an experimental API — `unstable_instant` is
`version: draft` and still reshaping (`unstable_prefetch` just split off
in #92754). The instant-navigation guide already covers the API in
measured language; agents working on slow-navigation tasks will find it
there.

<!-- NEXT_JS_LLM_PR -->
This PR cleans up small documentation and error-page issues: correct
TypeScript spelling where it was written as “Typescript”, use the proper
GitHub label in links, fix the MDN URL for `Map.prototype.values` in the
middleware upgrade guide.

No runtime or API behavior changes.
Reverts #92199.

Depends on #93802, which patches `playwright-core` to fix the root
cause: the client-side `Response._finishedPromise` was never resolved on
`requestFailed`, causing `response.finished()` to hang indefinitely and
surface as opaque 60s Jest timeouts in router-act-using tests.

With that patch in place, the cached-navigations tests can be
reinstated. This PR's CI is part of the verification path — the
previously-flaky tests now run cleanly through the 3× flake-detection
job.

<!-- NEXT_JS_LLM_PR -->
…93294)

In a Pages Router app that combines a `basePath`, `next.config.js`
`rewrites`, middleware, and a catch-all dynamic route, a client-side
`Link` navigation could land on the page with a corrupted
`router.query`. Instead of holding the captured route segments, the
catch-all param ended up holding the segments of the internal
`_next/data/<buildId>/...` URL. Page code that builds further URLs from
`router.query` then produced malformed paths and 404s in production.

The corruption originated in `getMiddlewareData`, which was passing
`nextConfig: undefined` to `getNextPathnameInfo` whenever
`__NEXT_HAS_REWRITES` was true. With basePath set, that meant the
basePath prefix was never stripped from the data-source URL, so the
`/_next/data/` check never matched and the data prefix was left intact.
The resulting pathname flowed back into `routeInfo.resolvedAs`, and on
catch-all routes the route regex matched it and overwrote
`router.query.<param>` with the data-URL segments.

The original ternary at this call site (added in #48753) was there to
avoid stripping the locale prefix, since `resolveRewrites` needs `as` to
keep its locale prefix to match locale-aware rewrite sources. Disabling
all of `nextConfig` was too coarse and broke basePath stripping in the
process. The fix passes a partial config with only `basePath` and
`trailingSlash`, which keeps the locale prefix intact while still
letting `getNextPathnameInfo` strip basePath before the data-prefix
check.

The new `test/e2e/middleware-dynamic-basepath-matcher-rewrites/` fixture
is the catch-all + basePath + rewrites + middleware variant of
`test/e2e/middleware-dynamic-basepath-matcher/` (#48753's regression
test), and asserts that `router.query.path` is preserved across a
client-side `Link` navigation.
we were invoking

```
xargs --null -n1 -I'{}' ...
```
to tell xargs that we want to:
- use 1 argument per invocation (`-n1`)
- `{}` is the placeholder (`-I'{}'`)

but it seems like `-I'{}'` already implies `-n1`. BSD xargs doesn't
care, but GNU xargs warns about it, so we get this in CI (e.g.
[here](https://github.com/vercel/next.js/actions/runs/25789455488/job/75751231855?pr=93801#step:36:54)):
```
xargs: warning: options --max-args and --replace/-I/-i are mutually exclusive, ignoring previous --max-args value
```

seems like both GNU and BSD xargs are happy if we just drop the `-n1`
and only use `-I{}`.
yesterday, PR #93399 introduced some non-sequential codes into
`errors.json`, which seems to mess with `scripts/merge-errors-json`, the
script responsible for automatically re-numbering error codes to fix
conflicts. i can fix the script later but for now as a workaround let's
just fix the error codes manually
@pull pull Bot locked and limited conversation to collaborators May 13, 2026
@pull pull Bot added the ⤵️ pull label May 13, 2026
lukesandberg and others added 4 commits May 13, 2026 14:25
## Summary

This is a re-application of #91729 without the TTL support (fetch
`Cache-Control` and `TransientState` changes are excluded).

### Make `session_dependent` a function attribute

Previously, tasks called `mark_session_dependent()` at runtime to flag
themselves. This PR makes it a compile-time
`#[turbo_tasks::function(session_dependent)]` attribute instead.
Benefits:

- **Enables eager aggregation number selection**: Session-dependent
tasks change on every session restore, behaving like dirty leaf nodes.
By knowing at task creation time (not mid-execution) that a task is
session-dependent, the backend can assign a high initial aggregation
number, preventing long dirty-propagation chains through intermediate
aggregated nodes.
- **Simpler API**: No runtime `mark_session_dependent()` call needed —
the attribute is declarative and statically checked.
- Removes `mark_session_dependent()`,
`mark_own_task_as_session_dependent()`, and the `session_dependent`
field from `InProgressStateInner`. The backend now reads
`is_session_dependent` directly from the `NativeFunction` metadata via
`TaskGuard::is_session_dependent()`.

## Test Plan

- Existing tests continue to pass
- `cargo check -p turbo-tasks -p turbo-tasks-backend -p
turbo-tasks-fetch`

## Why was #91729 reverted?

The original attempt seemed to be triggering OOMs on front. Through
debugging there were no obvious ways in which it was tied to this change
but rather due to invalidation races which motivated changes like #92389
to remove races from restore paths and #92814 which eliminated some
expensive errors from eventually consistent executions.

<!-- NEXT_JS_LLM_PR -->
When a `'use cache'` recorded an invalid dynamic usage error on the work
store (for example a `cookies()` call inside `'use cache'`, a
nested-dynamic `cacheLife`, or a `'use cache'` fill timeout),
`renderToHTMLOrFlight` used to throw the recorded error right after
`renderToStream` returned. The throw bubbled up through `base-server`
and ended up rendering the Pages-Router `/_error` page, which felt out
of place in an app-router context. This change removes that throw, so
the error reaches the dev overlay through the same Flight channel that
already surfaces static-shell-validation and instant-validation errors —
`logMessagesAndSendErrorsToBrowser`, called from
`spawnStaticShellValidationInDev` and from the validation-skipped
fallback in `generateDynamicFlightRenderResultWithStagesInDev`.

The original motivation for the throw was to avoid double-logging in the
uncaught case. Without it, both React's `serverComponentsErrorHandler`
(which stamps a digest and emits a Flight error chunk) and
`logMessagesAndSendErrorsToBrowser` would forward the same error. We now
dedupe by skipping the `logMessagesAndSendErrorsToBrowser` call whenever
the recorded error already carries a `digest`, since that is exactly the
signal that React has already seen it. Caught cases (no `digest`)
continue to surface through `logMessagesAndSendErrorsToBrowser` as a
collapsed dev-overlay entry; uncaught cases surface via React's Flight
error chunk as an auto-opened redbox.

This also sets us up for the upstack PR that attaches the inner cache
call site as `cause` of the nested-dynamic prerender error. With errors
now travelling uniformly over Flight — which preserves `cause` natively
— the cause flows straight through to the dev overlay without needing to
serialize it into the error page.
[diff
react/react@dd453071...d5736f09](react/react@dd45307...d5736f0)

<details>
<summary>React upstream changes</summary>

- react/react#36386

</details>

---------

Co-authored-by: next-js-bot[bot] <279046576+next-js-bot[bot]@users.noreply.github.com>
When a `"use cache"` propagated a dynamic cache life (`revalidate: 0` or
`expire` under 5 minutes) to a parent without an explicit `cacheLife`,
the resulting error pointed only at the outer cache invocation. With the
inner cache's call site missing, tracing which nested cache was
responsible meant reading through the outer's body — fine when it's
local code, much harder when the dynamism comes from a nested cache
buried in a third-party dependency.

This change attaches the inner invocation as `cause` of the error, so
the dev redbox and the build log show two stacks: the outer that threw,
and the inner that propagated the dynamic life.

The inner call site has to be captured eagerly while `cache()` is still
on the synchronous stack, because we only learn whether the inner
resolved dynamic asynchronously — after `collectResult` finishes and
`propagateCacheEntryMetadata` runs — and by then the inner's frames are
no longer on the JS stack. We only construct the eager `Error` when the
parent is itself a public `"use cache"` (the only case where this entry
could become a propagated origin), so top-level caches skip the
allocation. The eager `Error` is held on
`cacheContext.dynamicNestedCacheError`; once propagation knows the inner
resolved dynamic, it's copied onto the outer store's same-named field,
then carried through the outer's own `collectResult` into its RDC entry
— which the throw site finally reads back as `cause`. We keep the first
dynamic child — the immediate origin from the throwing cache's
perspective.

The two nested-dynamic cache error messages also get a small cleanup:
each used to write `"use cache"` two different ways within the same
sentence (bare and backticked); both now write it the same way.

<img width="2188" height="2662"
alt="localhost_3000_use-cache-low-expire_nested (1)"
src="https://github.com/user-attachments/assets/f5103e0e-b9c0-44c5-b93b-82981aa05219"
/>
@pull pull Bot merged commit 7dc4cdd into code:canary May 13, 2026
1 check passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants