[pull] canary from vercel:canary#1045
Merged
Merged
Conversation
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
## 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" />
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 : )