Skip to content

Polish instant fix cards and validation messages#93894

Draft
aurorascharff wants to merge 32 commits into
canaryfrom
aurorascharff/revamp-fix-cards
Draft

Polish instant fix cards and validation messages#93894
aurorascharff wants to merge 32 commits into
canaryfrom
aurorascharff/revamp-fix-cards

Conversation

@aurorascharff
Copy link
Copy Markdown
Contributor

@aurorascharff aurorascharff commented May 16, 2026

What?

Polish pass on the instant validation overlay and CLI messages.
TODO add new block icon (browser spinner)

Why?

Feedback from testing.

Demo

How

  • Cards: renamed GSP and metadata cards to read as plain English (Prerender params if known, Mark the route as dynamic), simplified client sync IO snippets to drop hooks, renamed the Profile card (For telemetry, use a timing API), removed viewport Wrap body in Suspense from both variants.
  • Build/overlay messages: body errors now say during prerendering and blocking the page load; server sync IO names the unstable value …; client sync IO drops fixed at build time; bullets aligned with the cards.
  • Overlay UX: subtle whole-card hover (border + bg + link-icon + snippet border), no more clipped bottom border on the snippet, scrollbar-gutter: stable to stop the dialog scrollbar flashing on error swap.

E2E snapshots refreshed across instant-validation*, cache-components-*, and build-output-prerender.

aurorascharff and others added 30 commits May 14, 2026 11:08
Adds two pieces of framework correctness for `unstable_instant` validation:

1. **Navigation body factories** in `blocking-route-messages.ts`:
   - `createRuntimeBodyErrorInNavigation` (E1247)
   - `createDynamicBodyErrorInNavigation` (E1246)
   Wired into `trackDynamicHoleInNavigation` so the in-navigation case emits
   its own message ("accessed under `<Suspense>`" + nav-aware "Ways to fix")
   instead of reusing the initial-render copy ("accessed outside of
   `<Suspense>`"). Phase-neutral phrasing ("during the initial render or a
   navigation") accommodates the path firing from either prerender or
   client-nav validation.

2. **Clear-on-nav reducer** in the dev overlay:
   - `ACTION_INSTANT_ERRORS_CLEAR` reducer case in `shared.ts`.
   - `useClearInstantErrorsOnNav` hook in `dev-overlay.tsx` watches
     `usePathname()` and dispatches when the route changes.
   Only errors fired during a client navigation are eligible to clear:
   `*InNavigation` factories carry an `__nextInstantNav` marker, and wrapper
   headlines (E1082 / E1112 / E1113 / E1118) are detected via the stable
   "Could not validate `unstable_instant`" substring. Initial-render / SSR
   errors lack both signals and persist, so a page that fails to prerender
   stays in the overlay until the source is fixed.

Co-authored-by: Cursor <[email protected]>
Reads the `__nextInstantNav` marker from the error to pick the right
overlay copy for the blocking-route family:

- Headline: "Next.js encountered runtime/uncached data during a
  navigation." (in-nav) vs. "during the initial render." (initial).
- Explanation: "This prevents the navigation from being instant..." vs.
  the default "prevents the route from being prerendered..." string.

Adds `BLOCKING_ROUTE_NAVIGATION_EXPLANATION` next to `EXPLANATIONS` in
`instant-guidance-data.ts` so all overlay copy stays in one place.

Also renames the legacy `'navigation'` value of `GuidanceVariant` to
`'dynamic'` — the original name meant "uncached data" (from #92638) and
collides with the new in-navigation concept. The new shape is
`'runtime' | 'dynamic'` for what kind of data is accessed, plus an
orthogonal `inNavigation: boolean` for the phase.

Co-authored-by: Cursor <[email protected]>
Object markers on the Error don't survive RSC serialization
(`__NEXT_ERROR_CODE` already has a side-channel Map for this same
reason), so the previous `__nextInstantNav` property was getting
stripped before the dev overlay ever saw it.

Switches detection to two structural substrings already present in the
user-facing copy:

- \`accessed under \`<Suspense>\`\` — only emitted by the in-navigation
  body factories. The mirrored SSR factories say \`accessed outside of
  \`<Suspense>\`\`, so the two are unambiguous.
- \`Could not validate \`unstable_instant\`\` — already used to detect
  wrapper errors (E1082 / E1112 / E1113 / E1118), tied to the API name
  rather than phase wording.

Drops the marker helper from `blocking-route-messages.ts`.

Co-authored-by: Cursor <[email protected]>
The dev overlay renders in a separate React root mounted at the document
body (via `createRoot(container)` in `dev-overlay.browser.tsx`), so the
App Router's `PathnameContext` isn't in scope and `usePathname()` returns
`null` — making the previous `useClearInstantErrorsOnNav` effect a no-op.

Switches to a browser-level subscription: listen for `popstate` (back /
forward) and patch `history.pushState` / `history.replaceState` to detect
client navigations triggered by `next/link` and `router.push()`. Cleanup
restores the originals so the patch is scoped to overlay lifetime.

This matches the pattern other dev-overlay code already uses for current
path (e.g. `route-info.tsx` reads `window.location.pathname` directly).

Co-authored-by: Cursor <[email protected]>
Co-authored-by: Cursor <[email protected]>
The new `createRuntimeBodyErrorInNavigation` / `createDynamicBodyErrorInNavigation`
factories produce "encountered runtime data during a navigation" wording in
the dev overlay (via inNavigation substring detection in errors.tsx). Seven
inline snapshots in instant-validation-parallel-slots.test.ts locked in the
older "during the initial render" + E1221 / E1220 wording — flipped to the
new "during a navigation" + E1247 / E1246.

The eighth test in this file is left at canary state: it relies on PR #93770's
"expected segment was not rendered" message which currently bakes in a
test/tmp/next-test-… absolute path. That test is broken on canary HEAD
too (verified directly) — not a regression from this PR.

Co-authored-by: Cursor <[email protected]>
`instant-validation.test.ts` (28 snapshots) and
`instant-validation-parallel-slots.test.ts` (7 snapshots) had build-mode
inline snapshots that pinned the older `createRuntimeBodyError` /
`createDynamicBodyError` wording. Switched to the new in-navigation
factory output:

  - "encountered runtime data during the initial render."
  + "encountered runtime data during the initial render or a navigation."

  - "accessed outside of `<Suspense>` prevents the route from being
    prerendered, blocking navigation and leading to a slower user
    experience."
  + "accessed under `<Suspense>` prevents the route from being
    prerendered or the navigation from being instant, leading to a
    slower user experience."

Captured without NEXT_SKIP_ISOLATE so the test packed next.js as a
tarball (matching the CI build path); avoids leaking local
`../../../packages/next/dist/esm/...` stack frames into the snapshots.

Co-authored-by: Cursor <[email protected]>
The in-navigation body factories said "accessed under \`<Suspense>\`",
which contradicts the fix bullet that recommends wrapping in Suspense.
The actual problem is the same as the SSR factories: data accessed
*outside* a Suspense boundary, where the prerender / prefetchable
shell can't proceed without waiting. Aligned both InNavigation factories
to "accessed outside of \`<Suspense>\`" so the diagnostic matches the
SSR factories — only the consequence clause differs (still includes
"or the navigation from being instant").

Refactored the substring detection that distinguishes in-navigation
vs SSR variants into a single `isBlockingRouteInNavError` helper in
`shared.ts`, used by both `getInstantErrorRoute` (clear-on-nav) and
`getBlockingRouteErrorDetails` (overlay headline phase). Helper keys
off "or a navigation" which is still unique to the InNavigation factory
pair (the diagnostic clause is now shared).

Also narrowed `getInstantErrorRoute` to detect *only* body factory
errors — wrapper errors like "Could not validate \`unstable_instant\`"
are no longer cleared on navigation. They describe a validation
infrastructure failure rather than a fixable route-level mistake and
should stay in the redbox stack until the user addresses the cause.

Snapshot updates across `instant-validation.test.ts` (dev + build
modes) and `instant-validation-parallel-slots.test.ts` (dev + build
modes) reflect the new wording. Build-mode snapshots captured without
NEXT_SKIP_ISOLATE so the test packs Next.js as a tarball and produces
the same stack frame shape CI sees (avoids leaking local dist paths).

Co-authored-by: Cursor <[email protected]>
- Drop history.pushState/replaceState patching in favor of state.page
  from ACTION_DEVTOOL_UPDATE_ROUTE_STATE (cooperates with App Router's
  own history patching).
- Update errors.test.ts for new {inNavigation, variant: 'dynamic'} shape
  and add InNavigation factory cases.
- Bump E1246/E1247 -> E1249/E1250 in level-* and causes tests after the
  factory wording change.

Co-authored-by: Cursor <[email protected]>
- Restore the 13-space indent on `Unrendered segment(s):` paths in dev
  inline snapshots (got stripped during the earlier wording sweep).
- Use the stable `app/...` prefix instead of the non-deterministic
  `test/tmp/next-test-<timestamp>-<rand>/...` path that crept into one
  parallel-slots snapshot.

Co-authored-by: Cursor <[email protected]>
`state.page` is the resolved URL (e.g. `/foo/123`), but an instant error's
embedded `Route "..."` uses the route pattern (`/foo/[param]`). Firing
the clear action on the initial '' → page transition would always wipe
dynamic-route errors before the redbox could open. Treat the first
non-empty page as the baseline and only dispatch on subsequent changes.

Co-authored-by: Cursor <[email protected]>
The SSR `createRuntimeBodyError` lists the Suspense placeholder first
(the most general fix) followed by `generateStaticParams`. The
in-navigation variant had them flipped, so the top-of-list suggestion
was the narrower one (only applies to dynamic-param routes). Reorder
the in-nav factory to match SSR, and refresh the build-mode CLI
snapshots and the runtime-body in-nav error code (E1250 → E1251).

Co-authored-by: Cursor <[email protected]>
The earlier wording sweep on the level-* tests preserved the pre-existing
2-space-shy indent on the `code` and `description` lines, so Jest's diff
reported a whitespace-only mismatch even though the values agreed. Match
them to the sibling JSON keys (13 spaces).

Co-authored-by: Cursor <[email protected]>
The previous patch overshot to 13 spaces in tests where the snapshot
braces sit two columns shallower (so sibling keys are at 11). Auto-align
each `code`/`description` line to the indent of the next sibling key.

Co-authored-by: Cursor <[email protected]>
`trackDynamicHoleInNavigation` is also reached during the build-time
prerender pass, so the CLI build error now reads "during the initial
render or a navigation" with the matching consequence clause. Update
the build-mode snapshots in `instant-validation-build` and the four
`instant-validation-level-*` tests to match.

Co-authored-by: Cursor <[email protected]>
…ording

The earlier wording sweep also touched the 4 \`without-root-suspense\`
E1220 snapshots, which come from the SSR factory (initial-render path)
and should keep "during the initial render." Restore the SSR wording
on those four.

Co-authored-by: Cursor <[email protected]>
`Route "<path>":` in the error message is the route template
(e.g. `/foo/[slug]`), while `state.page` is the resolved URL
(e.g. `/foo/123`). Equality matching dropped SSR-streamed errors
on the destination page during navigation for any dynamic route.

Convert the template to a regex so the clear-on-nav reducer keeps
errors whose template matches the page the user just landed on.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 16, 2026

Failing test suites

Commit: 1900b73 | About building and testing Next.js

pnpm test-dev test/e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts (job)

  • instant validation - level error > dev > bare page: implicit validation surfaces a redbox (error level fires) (DD)
  • instant validation - level error > dev > explicit-error page: explicit override at the configured level, instant redbox in dev (DD)
  • instant validation - level error > dev > explicit-true page: aliases to error level, instant redbox in dev (DD)
  • instant validation - level error > dev > explicit-warning page: per-segment de-escalation still validates in dev (DD)
  • instant validation - level error > dev > layered: bare page under layout-with-instant-false still validates (DD)
Expand output

● instant validation - level error › dev › bare page: implicit validation surfaces a redbox (error level fires)

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level error dev bare page: implicit validation surfaces a redbox (error level fires) 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/bare/page.tsx (11:19) @ Page
  > 11 |   await connection()

  59 |       it('bare page: implicit validation surfaces a redbox (error level fires)', async () => {
  60 |         const browser = await next.browser('/bare')
> 61 |         await expect(browser).toDisplayCollapsedRedbox(`
     |                               ^
  62 |          {
  63 |            "code": "E1249",
  64 |            "description": "Next.js encountered uncached data during a navigation.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts:61:31)

● instant validation - level error › dev › explicit-error page: explicit override at the configured level, instant redbox in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level error dev explicit-error page: explicit override at the configured level, instant redbox in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/explicit-error/page.tsx (8:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/explicit-error/page.tsx (11:19) @ Page
  > 11 |   await connection()

  77 |       it('explicit-error page: explicit override at the configured level, instant redbox in dev', async () => {
  78 |         const browser = await next.browser('/explicit-error')
> 79 |         await expect(browser).toDisplayCollapsedRedbox(`
     |                               ^
  80 |          {
  81 |            "cause": [
  82 |              {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts:79:31)

● instant validation - level error › dev › explicit-true page: aliases to error level, instant redbox in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level error dev explicit-true page: aliases to error level, instant redbox in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/explicit-true/page.tsx (9:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/explicit-true/page.tsx (12:19) @ Page
  > 12 |   await connection()

  107 |       it('explicit-true page: aliases to error level, instant redbox in dev', async () => {
  108 |         const browser = await next.browser('/explicit-true')
> 109 |         await expect(browser).toDisplayCollapsedRedbox(`
      |                               ^
  110 |          {
  111 |            "cause": [
  112 |              {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts:109:31)

● instant validation - level error › dev › explicit-warning page: per-segment de-escalation still validates in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level error dev explicit-warning page: per-segment de-escalation still validates in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/explicit-warning/page.tsx (8:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/explicit-warning/page.tsx (11:19) @ Page
  > 11 |   await connection()

  137 |       it('explicit-warning page: per-segment de-escalation still validates in dev', async () => {
  138 |         const browser = await next.browser('/explicit-warning')
> 139 |         await expect(browser).toDisplayCollapsedRedbox(`
      |                               ^
  140 |          {
  141 |            "cause": [
  142 |              {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts:139:31)

● instant validation - level error › dev › layered: bare page under layout-with-instant-false still validates

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level error dev layered: bare page under layout-with-instant-false still validates 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/layered/page.tsx (8:19) @ Page
  >  8 |   await connection()

  176 |         // page should still surface an instant redbox in dev.
  177 |         const browser = await next.browser('/layered')
> 178 |         await expect(browser).toDisplayCollapsedRedbox(`
      |                               ^
  179 |          {
  180 |            "code": "E1249",
  181 |            "description": "Next.js encountered uncached data during a navigation.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts:178:31)

pnpm test-dev test/e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts (job)

  • instant validation - level manual-error > dev > explicit-error page: explicit override at the configured level, instant redbox in dev (DD)
  • instant validation - level manual-error > dev > explicit-true page: aliases to error level, instant redbox in dev (DD)
  • instant validation - level manual-error > dev > explicit-warning page: per-segment de-escalation still validates in dev (DD)
Expand output

● instant validation - level manual-error › dev › explicit-error page: explicit override at the configured level, instant redbox in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-error dev explicit-error page: explicit override at the configured level, instant redbox in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/explicit-error/page.tsx (8:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/explicit-error/page.tsx (11:19) @ Page
  > 11 |   await connection()

  66 |       it('explicit-error page: explicit override at the configured level, instant redbox in dev', async () => {
  67 |         const browser = await next.browser('/explicit-error')
> 68 |         await expect(browser).toDisplayCollapsedRedbox(`
     |                               ^
  69 |          {
  70 |            "cause": [
  71 |              {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts:68:31)

● instant validation - level manual-error › dev › explicit-true page: aliases to error level, instant redbox in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-error dev explicit-true page: aliases to error level, instant redbox in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/explicit-true/page.tsx (9:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/explicit-true/page.tsx (12:19) @ Page
  > 12 |   await connection()

   96 |       it('explicit-true page: aliases to error level, instant redbox in dev', async () => {
   97 |         const browser = await next.browser('/explicit-true')
>  98 |         await expect(browser).toDisplayCollapsedRedbox(`
      |                               ^
   99 |          {
  100 |            "cause": [
  101 |              {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts:98:31)

● instant validation - level manual-error › dev › explicit-warning page: per-segment de-escalation still validates in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-error dev explicit-warning page: per-segment de-escalation still validates in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/explicit-warning/page.tsx (8:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/explicit-warning/page.tsx (11:19) @ Page
  > 11 |   await connection()

  126 |       it('explicit-warning page: per-segment de-escalation still validates in dev', async () => {
  127 |         const browser = await next.browser('/explicit-warning')
> 128 |         await expect(browser).toDisplayCollapsedRedbox(`
      |                               ^
  129 |          {
  130 |            "cause": [
  131 |              {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts:128:31)

pnpm test-dev test/e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts (job)

  • instant validation - level manual-warning > with-root-suspense > dev > explicit-error page: instant redbox surfaces under manual-warning (DD)
  • instant validation - level manual-warning > with-root-suspense > dev > explicit-true page: opt-in falls back to warning level, instant redbox in dev (DD)
  • instant validation - level manual-warning > with-root-suspense > dev > explicit-warning page: instant redbox in dev (DD)
  • instant validation - level manual-warning > without-root-suspense > dev > bare page: static-shell error surfaces but is not labelled Instant (DD)
  • instant validation - level manual-warning > without-root-suspense > dev > explicit-error page: instant redbox surfaces (instant subsumes static-shell when active) (DD)
  • instant validation - level manual-warning > without-root-suspense > dev > explicit-true page: instant redbox surfaces in dev (DD)
  • instant validation - level manual-warning > without-root-suspense > dev > explicit-warning page: instant redbox surfaces in dev (DD)
Expand output

● instant validation - level manual-warning › with-root-suspense › dev › explicit-error page: instant redbox surfaces under manual-warning

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-warning with-root-suspense dev explicit-error page: instant redbox surfaces under manual-warning 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/with-root-suspense/explicit-error/page.tsx (8:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/with-root-suspense/explicit-error/page.tsx (11:19) @ Page
  > 11 |   await connection()

  80 |             '/with-root-suspense/explicit-error'
  81 |           )
> 82 |           await expect(browser).toDisplayCollapsedRedbox(`
     |                                 ^
  83 |            {
  84 |              "cause": [
  85 |                {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts:82:33)

● instant validation - level manual-warning › with-root-suspense › dev › explicit-true page: opt-in falls back to warning level, instant redbox in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-warning with-root-suspense dev explicit-true page: opt-in falls back to warning level, instant redbox in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/with-root-suspense/explicit-true/page.tsx (7:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/with-root-suspense/explicit-true/page.tsx (10:19) @ Page
  > 10 |   await connection()

  112 |             '/with-root-suspense/explicit-true'
  113 |           )
> 114 |           await expect(browser).toDisplayCollapsedRedbox(`
      |                                 ^
  115 |            {
  116 |              "cause": [
  117 |                {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts:114:33)

● instant validation - level manual-warning › with-root-suspense › dev › explicit-warning page: instant redbox in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-warning with-root-suspense dev explicit-warning page: instant redbox in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/with-root-suspense/explicit-warning/page.tsx (6:33)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1249",
+   "code": "E1264",
    "description": "Next.js encountered uncached data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/with-root-suspense/explicit-warning/page.tsx (9:19) @ Page
  >  9 |   await connection()

  144 |             '/with-root-suspense/explicit-warning'
  145 |           )
> 146 |           await expect(browser).toDisplayCollapsedRedbox(`
      |                                 ^
  147 |            {
  148 |              "cause": [
  149 |                {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts:146:33)

● instant validation - level manual-warning › without-root-suspense › dev › bare page: static-shell error surfaces but is not labelled Instant

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-warning without-root-suspense dev bare page: static-shell error surfaces but is not labelled Instant 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1220",
+   "code": "E1265",
    "description": "Next.js encountered uncached data during prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/without-root-suspense/bare/page.tsx (10:19) @ Page
  > 10 |   await connection()

  228 |           // the "Instant" label — that's the proof that instant validation
  229 |           // did not run under 'manual-warning'.
> 230 |           await expect(browser).toDisplayCollapsedRedbox(`
      |                                 ^
  231 |            {
  232 |              "code": "E1220",
  233 |              "description": "Next.js encountered uncached data during prerendering.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts:230:33)

● instant validation - level manual-warning › without-root-suspense › dev › explicit-error page: instant redbox surfaces (instant subsumes static-shell when active)

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-warning without-root-suspense dev explicit-error page: instant redbox surfaces (instant subsumes static-shell when active) 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1220",
+   "code": "E1265",
    "description": "Next.js encountered uncached data during prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/without-root-suspense/explicit-error/page.tsx (11:19) @ Page
  > 11 |   await connection()

  248 |             '/without-root-suspense/explicit-error'
  249 |           )
> 250 |           await expect(browser).toDisplayCollapsedRedbox(`
      |                                 ^
  251 |            {
  252 |              "code": "E1220",
  253 |              "description": "Next.js encountered uncached data during prerendering.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts:250:33)

● instant validation - level manual-warning › without-root-suspense › dev › explicit-true page: instant redbox surfaces in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-warning without-root-suspense dev explicit-true page: instant redbox surfaces in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1220",
+   "code": "E1265",
    "description": "Next.js encountered uncached data during prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/without-root-suspense/explicit-true/page.tsx (11:19) @ Page
  > 11 |   await connection()

  268 |             '/without-root-suspense/explicit-true'
  269 |           )
> 270 |           await expect(browser).toDisplayCollapsedRedbox(`
      |                                 ^
  271 |            {
  272 |              "code": "E1220",
  273 |              "description": "Next.js encountered uncached data during prerendering.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts:270:33)

● instant validation - level manual-warning › without-root-suspense › dev › explicit-warning page: instant redbox surfaces in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation - level manual-warning without-root-suspense dev explicit-warning page: instant redbox surfaces in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1220",
+   "code": "E1265",
    "description": "Next.js encountered uncached data during prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/without-root-suspense/explicit-warning/page.tsx (10:19) @ Page
  > 10 |   await connection()

  288 |             '/without-root-suspense/explicit-warning'
  289 |           )
> 290 |           await expect(browser).toDisplayCollapsedRedbox(`
      |                                 ^
  291 |            {
  292 |              "code": "E1220",
  293 |              "description": "Next.js encountered uncached data during prerendering.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts:290:33)

pnpm test-dev test/e2e/app-dir/instant-validation-static-shells/instant-validation-static-shells.test.ts (job)

  • instant validation > requires a static shell if a below a static layout page is configured as blocking > errors in dev (DD)
Expand output

● instant validation › requires a static shell if a below a static layout page is configured as blocking › errors in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation requires a static shell if a below a static layout page is configured as blocking errors in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1220",
+   "code": "E1265",
    "description": "Next.js encountered uncached data during prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/blocking-page-below-static/page.tsx (6:19) @ Page
  > 6 |   await connection()

  44 |         const browser = await next.browser('/blocking-page-below-static')
  45 |         await browser.elementByCss('main')
> 46 |         await expect(browser).toDisplayCollapsedRedbox(`
     |                               ^
  47 |          {
  48 |            "code": "E1220",
  49 |            "description": "Next.js encountered uncached data during prerendering.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-static-shells/instant-validation-static-shells.test.ts:46:31)

pnpm test-dev test/e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts (job)

  • instant validation causes > named export - export { unstable_instant } (DD)
  • instant validation causes > aliased export - export { instant as unstable_instant } (DD)
  • instant validation causes > re-export - export { unstable_instant } from "./config" (DD)
  • instant validation causes > indirect export - const instant = _instant; export { instant as unstable_instant } (DD)
Expand output

● instant validation causes › named export - export { unstable_instant }

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation causes named export - export { unstable_instant } 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/named-export/page.tsx (3:26)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1251",
+   "code": "E1271",
    "description": "Next.js encountered runtime data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/named-export/page.tsx (7:16) @ Page
  >  7 |   await cookies()

  92 |     const browser = await next.browser('/named-export')
  93 |     await waitForValidation(await browser.url())
> 94 |     await expect(browser).toDisplayCollapsedRedbox(`
     |                           ^
  95 |      {
  96 |        "cause": [
  97 |          {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts:94:27)

● instant validation causes › aliased export - export { instant as unstable_instant }

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation causes aliased export - export { instant as unstable_instant } 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/aliased-export/page.tsx (3:17)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1251",
+   "code": "E1271",
    "description": "Next.js encountered runtime data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/aliased-export/page.tsx (7:16) @ Page
  >  7 |   await cookies()

  123 |     const browser = await next.browser('/aliased-export')
  124 |     await waitForValidation(await browser.url())
> 125 |     await expect(browser).toDisplayCollapsedRedbox(`
      |                           ^
  126 |      {
  127 |        "cause": [
  128 |          {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts:125:27)

● instant validation causes › re-export - export { unstable_instant } from "./config"

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation causes re-export - export { unstable_instant } from "./config" 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/reexport/page.tsx (3:10)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1251",
+   "code": "E1271",
    "description": "Next.js encountered runtime data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/reexport/page.tsx (6:16) @ Page
  > 6 |   await cookies()

  154 |     const browser = await next.browser('/reexport')
  155 |     await waitForValidation(await browser.url())
> 156 |     await expect(browser).toDisplayCollapsedRedbox(`
      |                           ^
  157 |      {
  158 |        "cause": [
  159 |          {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts:156:27)

● instant validation causes › indirect export - const instant = _instant; export { instant as unstable_instant }

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation causes indirect export - const instant = _instant; export { instant as unstable_instant } 1`

- Snapshot  - 1
+ Received  + 1

@@ -9,11 +9,11 @@
          "unstable_instant app/indirect-export/page.tsx (4:17)",
          "Set.forEach <anonymous>",
        ],
      },
    ],
-   "code": "E1251",
+   "code": "E1271",
    "description": "Next.js encountered runtime data during a navigation.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/indirect-export/page.tsx (8:16) @ Page
  >  8 |   await cookies()

  188 |     // We're not following declarations recursively mostly to keep the implementation simpler
  189 |     // presuming that almost all configs are just `export const instant = ...`
> 190 |     await expect(browser).toDisplayCollapsedRedbox(`
      |                           ^
  191 |      {
  192 |        "cause": [
  193 |          {

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts:190:27)

pnpm test-dev test/e2e/app-dir/instant-validation-static-shells/instant-validation-static-shells.test.ts (job)

  • instant validation > requires a static shell if a below a static layout page is configured as blocking > errors in dev (DD)
Expand output

● instant validation › requires a static shell if a below a static layout page is configured as blocking › errors in dev

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `instant validation requires a static shell if a below a static layout page is configured as blocking errors in dev 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1220",
+   "code": "E1265",
    "description": "Next.js encountered uncached data during prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/blocking-page-below-static/page.tsx (6:19) @ Page
  > 6 |   await connection()

  44 |         const browser = await next.browser('/blocking-page-below-static')
  45 |         await browser.elementByCss('main')
> 46 |         await expect(browser).toDisplayCollapsedRedbox(`
     |                               ^
  47 |          {
  48 |            "code": "E1220",
  49 |            "description": "Next.js encountered uncached data during prerendering.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/instant-validation-static-shells/instant-validation-static-shells.test.ts:46:31)

pnpm test-dev test/development/app-dir/cache-components-dev-errors/cache-components-dev-errors.test.ts (job)

  • Cache Components Dev Errors > should show a red box error on the SSR render (DD)
  • Cache Components Dev Errors > should not show a red box error on client navigations (DD)
  • Cache Components Dev Errors > should display error when component accessed data without suspense boundary (DD)
Expand output

● Cache Components Dev Errors › should show a red box error on the SSR render

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `Cache Components Dev Errors should show a red box error on the SSR render 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1242",
+   "code": "E1261",
    "description": "Next.js encountered the unstable value Math.random() while prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/error/page.tsx (2:23) @ Page
  > 2 |   const random = Math.random()

  20 |     // Interestingly, it only appears on initial load, and not when
  21 |     // soft-navigating to the page (see test below).
> 22 |     await expect(browser).toDisplayCollapsedRedbox(`
     |                           ^
  23 |      {
  24 |        "code": "E1242",
  25 |        "description": "Next.js encountered the unstable value Math.random() while prerendering.",

  at Object.toDisplayCollapsedRedbox (development/app-dir/cache-components-dev-errors/cache-components-dev-errors.test.ts:22:27)

● Cache Components Dev Errors › should not show a red box error on client navigations

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `Cache Components Dev Errors should not show a red box error on client navigations 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1242",
+   "code": "E1261",
    "description": "Next.js encountered the unstable value Math.random() while prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/error/page.tsx (2:23) @ Page
  > 2 |   const random = Math.random()

  50 |
  51 |     // TODO: React should not include the anon stack in the Owner Stack.
> 52 |     await expect(browser).toDisplayCollapsedRedbox(`
     |                           ^
  53 |      {
  54 |        "code": "E1242",
  55 |        "description": "Next.js encountered the unstable value Math.random() while prerendering.",

  at Object.toDisplayCollapsedRedbox (development/app-dir/cache-components-dev-errors/cache-components-dev-errors.test.ts:52:27)

● Cache Components Dev Errors › should display error when component accessed data without suspense boundary

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `Cache Components Dev Errors should display error when component accessed data without suspense boundary 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1220",
+   "code": "E1265",
    "description": "Next.js encountered uncached data during prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/no-accessed-data/page.js (2:9) @ Page
  > 2 |   await new Promise((r) => setTimeout(r, 200))

   97 |     )
   98 |
>  99 |     await expect(browser).toDisplayCollapsedRedbox(`
      |                           ^
  100 |      {
  101 |        "code": "E1220",
  102 |        "description": "Next.js encountered uncached data during prerendering.",

  at Object.toDisplayCollapsedRedbox (development/app-dir/cache-components-dev-errors/cache-components-dev-errors.test.ts:99:27)

pnpm test-dev test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts (job)

  • Cache Components Errors > Dev > Dynamic Metadata - Error Route > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Dynamic Root > should show a collapsed redbox with two errors (DD)
  • Cache Components Errors > Dev > Dynamic Viewport - Dynamic Route > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Dynamic Viewport - Static Route > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Error Attribution with Sync IO > Guarded RSC with unguarded Client sync IO > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Error Attribution with Sync IO > Unguarded RSC with guarded Client sync IO > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Error Attribution with Sync IO > unguarded RSC with unguarded Client sync IO > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > IO accessed in Client Components > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Inside use cache > cacheLife with expire < 5 minutes > microtasky cache > should show a redbox error (DD)
  • Cache Components Errors > Dev > Inside use cache > cacheLife with expire < 5 minutes > slow cache > should show a redbox error (DD)
  • Cache Components Errors > Dev > Inside use cache > cacheLife with revalidate: 0 > microtasky cache > should show a redbox error (DD)
  • Cache Components Errors > Dev > Inside use cache > cacheLife with revalidate: 0 > slow cache > should show a redbox error (DD)
  • Cache Components Errors > Dev > Inside use cache > reading fallback params > should show a redbox error (DD)
  • Cache Components Errors > Dev > Sync Dynamic Platform > With Fallback - Math.random() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync Dynamic Platform > Without Fallback - Math.random() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Current Time - Date() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Current Time - Date.now() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Current Time - new Date() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - generateKeyPairSync() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - generateKeySync() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - generatePrimeSync() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - getRandomValues() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - random-bytes() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - random-fill-sync() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - random-int-between() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - random-int-up-to() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Node Crypto - random-uuid > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Random - Math.random() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Web Crypto - getRandomValue() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > Sync IO - Web Crypto - randomUUID() > should show a collapsed redbox error (DD)
  • Cache Components Errors > Dev > With use cache: private > without Suspense > should show a redbox error (DD)
Expand output

● Cache Components Errors › Dev › Dynamic Metadata - Error Route › should show a collapsed redbox error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `Cache Components Errors Dev Dynamic Metadata - Error Route should show a collapsed redbox error 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1220",
+   "code": "E1265",
    "description": "Next.js encountered uncached data during prerendering.",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/dynamic-metadata-error-route/page.tsx (21:9) @ Dynamic
  > 21 |   await new Promise((r) => setTimeout(r))

  157 |           const browser = await next.browser(pathname)
  158 |
> 159 |           await expect(browser).toDisplayCollapsedRedbox(`
      |                                 ^
  160 |            {
  161 |              "code": "E1220",
  162 |              "description": "Next.js encountered uncached data during prerendering.",

  at Object.toDisplayCollapsedRedbox (e2e/app-dir/cache-components-errors/cache-components-errors.test.ts:159:33)

● Cache Components Errors › Dev › Dynamic Viewport - Static Route › should show a collapsed redbox error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `Cache Components Errors Dev Dynamic Viewport - Static Route should show a collapsed redbox error 1`

- Snapshot  - 1
+ Received  + 1

@@ -1,7 +1,7 @@
  {
-   "code": "E1210",
+   "code": "E1255",
    "description": "Next.js encountered uncached data in generateViewport().",
    "environmentLabel": "Server",
    "label": "Instant",
    "source": "app/dynamic-viewport-static-route/page.tsx (2:9) @ Module.generateViewport
  > 2 |   await new Promise((r) => setTimeout(r, 0))

  565 |           const bro

... truncated to fit in one GitHub comment ...

Base automatically changed from aurorascharff/instant-nav-error-clear to canary May 18, 2026 15:50
…/revamp-fix-cards

# Conflicts:
#	packages/next/src/next-devtools/dev-overlay/container/errors.tsx
#	test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts
#	test/e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts
#	test/e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts
#	test/e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts
#	test/e2e/app-dir/instant-validation-level-warning/instant-validation-level-warning.test.ts
#	test/e2e/app-dir/instant-validation/instant-validation-parallel-slots.test.ts
#	test/e2e/app-dir/instant-validation/instant-validation.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant