From f46db1c4a68e9785999380ff226838c5a43de10b Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com> Date: Mon, 18 May 2026 15:35:58 +0200 Subject: [PATCH 1/3] Pass projectDir to adapter modifyConfig (#93916) Adapters implementing `modifyConfig` may need to know the absolute project directory to perform path resolution or apply directory-specific configuration logic. Without this value, adapters had no reliable way to determine where the application lives on disk. onBuildComplete already received the directory as a parameter. --- .../07-adapters/02-creating-an-adapter.mdx | 1 + .../03-api-reference/07-adapters/03-api-reference.mdx | 1 + packages/next/src/build/adapter/build-complete.ts | 4 ++++ packages/next/src/server/config.ts | 11 +++++++---- .../adapter-config/adapter-config-export.test.ts | 1 + test/production/adapter-config/adapter-config.test.ts | 1 + 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/01-app/03-api-reference/07-adapters/02-creating-an-adapter.mdx b/docs/01-app/03-api-reference/07-adapters/02-creating-an-adapter.mdx index 081b135bbbb6..d3e51f2db4fd 100644 --- a/docs/01-app/03-api-reference/07-adapters/02-creating-an-adapter.mdx +++ b/docs/01-app/03-api-reference/07-adapters/02-creating-an-adapter.mdx @@ -42,6 +42,7 @@ export interface NextAdapter { ctx: { phase: PHASE_TYPE nextVersion: string + projectDir: string } ) => Promise | NextConfigComplete onBuildComplete?: (ctx: { diff --git a/docs/01-app/03-api-reference/07-adapters/03-api-reference.mdx b/docs/01-app/03-api-reference/07-adapters/03-api-reference.mdx index 4567c187bd4c..beac22e568e4 100644 --- a/docs/01-app/03-api-reference/07-adapters/03-api-reference.mdx +++ b/docs/01-app/03-api-reference/07-adapters/03-api-reference.mdx @@ -12,6 +12,7 @@ Called for any CLI command that loads the `next.config.js` file to allow modific - `config`: The complete Next.js configuration object - `context.phase`: The current build phase (see [phases](/docs/app/api-reference/config/next-config-js#phase)) - `context.nextVersion`: Version of Next.js being used +- `context.projectDir`: Absolute path to the Next.js project directory **Returns:** The modified configuration object (can be async) diff --git a/packages/next/src/build/adapter/build-complete.ts b/packages/next/src/build/adapter/build-complete.ts index 86db2bed9d77..cbd3ce28b81d 100644 --- a/packages/next/src/build/adapter/build-complete.ts +++ b/packages/next/src/build/adapter/build-complete.ts @@ -379,6 +379,10 @@ export interface NextAdapter { * nextVersion is the current version of Next.js being used */ nextVersion: string + /** + * projectDir is the absolute directory the Next.js application is in + */ + projectDir: string } ) => Promise | NextConfigComplete onBuildComplete?: (ctx: { diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 0fc91649ce85..36af419df631 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -1590,7 +1590,8 @@ function finalizeConfig(config: NextConfigComplete): NextConfigComplete { async function applyModifyConfig( config: NextConfigComplete, phase: PHASE_TYPE, - silent: boolean + silent: boolean, + dir: string ): Promise { // we always call modify config and phase can be used to only // modify for specific times @@ -1607,6 +1608,7 @@ async function applyModifyConfig( config = await adapterMod.modifyConfig(config, { phase, nextVersion: process.env.__NEXT_VERSION as string, + projectDir: dir, }) } } @@ -1779,7 +1781,8 @@ export default async function loadConfig( phase ), phase, - silent + silent, + dir ) ) @@ -1977,7 +1980,7 @@ export default async function loadConfig( ) const finalConfig = finalizeConfig( - await applyModifyConfig(completeConfig, phase, silent) + await applyModifyConfig(completeConfig, phase, silent, dir) ) // Cache the final result @@ -2036,7 +2039,7 @@ export default async function loadConfig( setHttpClientAndAgentOptions(completeConfig) const finalConfig = finalizeConfig( - await applyModifyConfig(completeConfig, phase, silent) + await applyModifyConfig(completeConfig, phase, silent, dir) ) // Cache the default config result diff --git a/test/production/adapter-config/adapter-config-export.test.ts b/test/production/adapter-config/adapter-config-export.test.ts index ddc75b5242fe..640f170741f1 100644 --- a/test/production/adapter-config/adapter-config-export.test.ts +++ b/test/production/adapter-config/adapter-config-export.test.ts @@ -55,6 +55,7 @@ describe('adapter-config export', () => { } expect(ctx.nextVersion).toBe(nextVersion) + expect(ctx.projectDir).toBe(next.testDir) expect(config?.basePath).toBe('/docs') const combinedRouteOutputs = [ diff --git a/test/production/adapter-config/adapter-config.test.ts b/test/production/adapter-config/adapter-config.test.ts index eedfb9506ac8..c93763880263 100644 --- a/test/production/adapter-config/adapter-config.test.ts +++ b/test/production/adapter-config/adapter-config.test.ts @@ -43,6 +43,7 @@ describe('adapter-config', () => { } expect(ctx.nextVersion).toBe(nextVersion) + expect(ctx.projectDir).toBe(next.testDir) expect(config?.basePath).toBe('/docs') const combinedRouteOutputs = [ From 15d2272c8ccdd34bef15ab2a46eccd27d1574691 Mon Sep 17 00:00:00 2001 From: Aurora Scharff <66901228+aurorascharff@users.noreply.github.com> Date: Mon, 18 May 2026 17:50:37 +0200 Subject: [PATCH 2/3] Distinguish in-navigation errors in the instant error overlay (#93843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What? When instant validation flags a route that can't load instantly, the overlay shows a warning. This PR (1) distinguishes nav-phase warnings from initial-render ones in the overlay text, and (2) clears the nav-phase warnings on route change so they don't accumulate after the user has moved on. ### Why? The redbox previously couldn't tell whether a route's instant warning was raised while rendering it directly or while navigating into it โ€” the text and stack looked the same. And once one was surfaced, it stuck around even after the user navigated elsewhere, where it was no longer actionable. The two changes together make each warning describe the phase that produced it and only stay visible while it's still relevant. ### Demo - Subnav under Suspense: [cookies](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/41-subnav-cookies) ยท [fetch](https://error-messages-overhaul-ibsl.labs.vercel.dev/scenario/42-subnav-fetch) ### How - New in-navigation variants of the body factory messages ("during the initial render or a navigation") let the overlay tell nav warnings apart from initial-render ones. The diagnostic clause stays aligned ("accessed outside of \`\`"); only the phase and consequence change. - The overlay reads the phase off the message, picks a matching headline, and on route change drops nav warnings while keeping initial-render errors in the redbox stack. - Renames the \`GuidanceVariant\` value (\`'navigation' โ†’ 'dynamic'\`) that collided with the new in-nav phase concept. --------- Co-authored-by: Cursor --- .../decorators/use-overlay-reducer.ts | 2 + packages/next/errors.json | 13 +- .../instant/instant-guidance-data.ts | 7 +- .../dev-overlay/container/errors.test.ts | 64 +++-- .../dev-overlay/container/errors.tsx | 48 +++- .../next-devtools/dev-overlay/dev-overlay.tsx | 25 +- .../next-devtools/dev-overlay/shared.test.ts | 99 +++++++ .../src/next-devtools/dev-overlay/shared.ts | 48 ++++ .../app-render/blocking-route-messages.ts | 24 ++ .../server/app-render/dynamic-rendering.ts | 6 +- .../instant-validation-build.test.ts | 4 +- .../instant-validation-causes.test.ts | 16 +- .../instant-validation-level-error.test.ts | 36 +-- ...tant-validation-level-manual-error.test.ts | 20 +- ...nt-validation-level-manual-warning.test.ts | 16 +- .../instant-validation-level-warning.test.ts | 24 +- .../instant-validation-parallel-slots.test.ts | 66 ++--- .../instant-validation.test.ts | 242 +++++++++--------- 18 files changed, 507 insertions(+), 253 deletions(-) create mode 100644 packages/next/src/next-devtools/dev-overlay/shared.test.ts diff --git a/packages/next/.storybook/decorators/use-overlay-reducer.ts b/packages/next/.storybook/decorators/use-overlay-reducer.ts index 88a4002151ef..b61c59edb8c5 100644 --- a/packages/next/.storybook/decorators/use-overlay-reducer.ts +++ b/packages/next/.storybook/decorators/use-overlay-reducer.ts @@ -11,6 +11,7 @@ import { ACTION_BUILDING_INDICATOR_HIDE, ACTION_BUILDING_INDICATOR_SHOW, ACTION_CACHE_INDICATOR, + ACTION_INSTANT_ERRORS_CLEAR, ACTION_INSTANT_NAVS_TOGGLE, ACTION_INSTANT_NAVS_RESET, ACTION_DEBUG_INFO, @@ -88,6 +89,7 @@ export function useStorybookOverlayReducer(initialState?: OverlayState) { case ACTION_RENDERING_INDICATOR_HIDE: case ACTION_RENDERING_INDICATOR_SHOW: case ACTION_CACHE_INDICATOR: + case ACTION_INSTANT_ERRORS_CLEAR: case ACTION_INSTANT_NAVS_TOGGLE: case ACTION_INSTANT_NAVS_RESET: case ACTION_STATIC_INDICATOR: diff --git a/packages/next/errors.json b/packages/next/errors.json index eb11c7890745..a0d180d3b8bd 100644 --- a/packages/next/errors.json +++ b/packages/next/errors.json @@ -1244,8 +1244,13 @@ "1243": "This \"use cache\" has a dynamic cache life that was propagated to its parent.", "1244": "A \"use cache\" with short \\`expire\\` (under 5 minutes) is nested inside another \"use cache\" that has no explicit \\`cacheLife\\`, which is not allowed during prerendering. Add \\`cacheLife()\\` to the outer \"use cache\" to choose whether it should be prerendered (with longer \\`expire\\`) or remain dynamic (with short \\`expire\\`). Read more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife", "1245": "A \"use cache\" with zero \\`revalidate\\` is nested inside another \"use cache\" that has no explicit \\`cacheLife\\`, which is not allowed during prerendering. Add \\`cacheLife()\\` to the outer \"use cache\" to choose whether it should be prerendered (with non-zero \\`revalidate\\`) or remain dynamic (with zero \\`revalidate\\`). Read more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife", - "1246": "Could not validate instant UI because an expected segment was not rendered.", - "1247": "\\`experimental.cssChunking: \"graph\"\\` is only supported with Turbopack. Please remove the option or run Next.js with Turbopack in %s.", - "1248": "\\`experimental.cssChunking: \"strict\"\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s.", - "1249": "\\`experimental.cssChunking: false\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s." + "1246": "Route \"%s\": Next.js encountered uncached data during the initial render or a navigation.\\n\\n\\`fetch(...)\\` or \\`connection()\\` accessed under \\`\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Cache the data access with \\`\"use cache\"\\`\\n - Provide a placeholder with \\`\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route", + "1247": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed under \\`\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Use \\`generateStaticParams\\` to make route params static\\n - Provide a placeholder with \\`\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route", + "1248": "Could not validate instant UI because an expected segment was not rendered.", + "1249": "Route \"%s\": Next.js encountered uncached data during the initial render or a navigation.\\n\\n\\`fetch(...)\\` or \\`connection()\\` accessed outside of \\`\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Cache the data access with \\`\"use cache\"\\`\\n - Provide a placeholder with \\`\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route", + "1250": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed outside of \\`\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Use \\`generateStaticParams\\` to make route params static\\n - Provide a placeholder with \\`\\` around the data access\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route", + "1251": "Route \"%s\": Next.js encountered runtime data during the initial render or a navigation.\\n\\n\\`cookies()\\`, \\`headers()\\`, \\`params\\`, or \\`searchParams\\` accessed outside of \\`\\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\\n\\nWays to fix this:\\n - Provide a placeholder with \\`\\` around the data access\\n - Use \\`generateStaticParams\\` to make route params static\\n - Set \\`export const instant = false\\` to allow a blocking route\\n\\nLearn more: https://nextjs.org/docs/messages/blocking-route", + "1252": "\\`experimental.cssChunking: \"graph\"\\` is only supported with Turbopack. Please remove the option or run Next.js with Turbopack in %s.", + "1253": "\\`experimental.cssChunking: \"strict\"\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s.", + "1254": "\\`experimental.cssChunking: false\\` is only supported with webpack. Please remove the option or run Next.js with webpack in %s." } diff --git a/packages/next/src/next-devtools/dev-overlay/components/instant/instant-guidance-data.ts b/packages/next/src/next-devtools/dev-overlay/components/instant/instant-guidance-data.ts index b776f8a8e667..1d6207dcb489 100644 --- a/packages/next/src/next-devtools/dev-overlay/components/instant/instant-guidance-data.ts +++ b/packages/next/src/next-devtools/dev-overlay/components/instant/instant-guidance-data.ts @@ -486,7 +486,7 @@ export type GuidanceKind = | 'sync-io' | 'sync-io-client' -export type GuidanceVariant = 'runtime' | 'navigation' +export type GuidanceVariant = 'runtime' | 'dynamic' export const DOCS_URLS: Record = { 'blocking-route': 'https://nextjs.org/docs/messages/blocking-route', @@ -562,6 +562,9 @@ export const EXPLANATIONS: Record = { 'This value would be evaluated during the prerender and fixed at build time, instead of recomputed on each visit.', } +export const BLOCKING_ROUTE_NAVIGATION_EXPLANATION = + 'This prevents the navigation from being instant, leading to a slower user experience.' + const syncCardsByCause: Record = { 'Math.random()': syncMathCards, 'Date.now()': syncDateCards, @@ -601,7 +604,7 @@ export function getCards( ): FixCard[] { switch (kind) { case 'blocking-route': - return variant === 'navigation' ? dynamicCards : runtimeCards + return variant === 'dynamic' ? dynamicCards : runtimeCards case 'metadata': return variant === 'runtime' ? metadataRuntimeCards : metadataDynamicCards case 'viewport': diff --git a/packages/next/src/next-devtools/dev-overlay/container/errors.test.ts b/packages/next/src/next-devtools/dev-overlay/container/errors.test.ts index dae0dfdfcfb8..395f7daad31c 100644 --- a/packages/next/src/next-devtools/dev-overlay/container/errors.test.ts +++ b/packages/next/src/next-devtools/dev-overlay/container/errors.test.ts @@ -1,11 +1,13 @@ import { createDynamicBodyError, + createDynamicBodyErrorInNavigation, createDynamicMetadataError, createDynamicOrRuntimeBodyError, createDynamicOrRuntimeMetadataError, createDynamicOrRuntimeViewportError, createDynamicViewportError, createRuntimeBodyError, + createRuntimeBodyErrorInNavigation, createRuntimeMetadataError, createRuntimeViewportError, } from '../../../server/app-render/blocking-route-messages' @@ -24,14 +26,6 @@ import { const ROUTE = '/example' -// Every detection helper in errors.tsx walks the user-facing error message -// produced by the server-side factories in `blocking-route-messages.ts` and -// `sync-io-messages.ts`. These tests guard the contract between the two -// modules: if a factory's wording shifts in a way the detector can't -// recognize, classification silently falls back to "not an instant error" -// and the overlay shows the wrong UI. Three regressions in this exact spot -// during the redesign motivated this test. - describe('isRuntimeVariant', () => { it('returns true for runtime body factory output', () => { expect(isRuntimeVariant(createRuntimeBodyError(ROUTE).message)).toBe(true) @@ -128,24 +122,48 @@ describe('isSyncIOClientError', () => { }) describe('getBlockingRouteErrorDetails', () => { - it('classifies createRuntimeBodyError as blocking-route + runtime', () => { + it('classifies createRuntimeBodyError as blocking-route + runtime (SSR-only)', () => { expect(getBlockingRouteErrorDetails(createRuntimeBodyError(ROUTE))).toEqual( - { type: 'blocking-route', variant: 'runtime' } + { type: 'blocking-route', variant: 'runtime', inNavigation: false } ) }) - it('classifies createDynamicBodyError as blocking-route + navigation', () => { + it('classifies createDynamicBodyError as blocking-route + dynamic (SSR-only)', () => { expect(getBlockingRouteErrorDetails(createDynamicBodyError(ROUTE))).toEqual( - { type: 'blocking-route', variant: 'navigation' } + { type: 'blocking-route', variant: 'dynamic', inNavigation: false } ) }) - it('classifies createDynamicOrRuntimeBodyError as blocking-route + navigation', () => { + it('classifies createRuntimeBodyErrorInNavigation as blocking-route + runtime + inNavigation', () => { + expect( + getBlockingRouteErrorDetails(createRuntimeBodyErrorInNavigation(ROUTE)) + ).toEqual({ + type: 'blocking-route', + variant: 'runtime', + inNavigation: true, + }) + }) + + it('classifies createDynamicBodyErrorInNavigation as blocking-route + dynamic + inNavigation', () => { + expect( + getBlockingRouteErrorDetails(createDynamicBodyErrorInNavigation(ROUTE)) + ).toEqual({ + type: 'blocking-route', + variant: 'dynamic', + inNavigation: true, + }) + }) + + it('classifies createDynamicOrRuntimeBodyError as blocking-route + dynamic (SSR-only)', () => { // The "either" factory has no clear runtime signal โ€” falls into the - // navigation branch by `isRuntimeVariant`. Documents current behavior. + // dynamic branch by `isRuntimeVariant`. Documents current behavior. expect( getBlockingRouteErrorDetails(createDynamicOrRuntimeBodyError(ROUTE)) - ).toEqual({ type: 'blocking-route', variant: 'navigation' }) + ).toEqual({ + type: 'blocking-route', + variant: 'dynamic', + inNavigation: false, + }) }) it('classifies createRuntimeMetadataError as dynamic-metadata + runtime', () => { @@ -154,16 +172,16 @@ describe('getBlockingRouteErrorDetails', () => { ).toEqual({ type: 'dynamic-metadata', variant: 'runtime' }) }) - it('classifies createDynamicMetadataError as dynamic-metadata + navigation', () => { + it('classifies createDynamicMetadataError as dynamic-metadata + dynamic', () => { expect( getBlockingRouteErrorDetails(createDynamicMetadataError(ROUTE)) - ).toEqual({ type: 'dynamic-metadata', variant: 'navigation' }) + ).toEqual({ type: 'dynamic-metadata', variant: 'dynamic' }) }) - it('classifies createDynamicOrRuntimeMetadataError as dynamic-metadata + navigation', () => { + it('classifies createDynamicOrRuntimeMetadataError as dynamic-metadata + dynamic', () => { expect( getBlockingRouteErrorDetails(createDynamicOrRuntimeMetadataError(ROUTE)) - ).toEqual({ type: 'dynamic-metadata', variant: 'navigation' }) + ).toEqual({ type: 'dynamic-metadata', variant: 'dynamic' }) }) it('classifies createRuntimeViewportError as dynamic-viewport + runtime', () => { @@ -172,16 +190,16 @@ describe('getBlockingRouteErrorDetails', () => { ).toEqual({ type: 'dynamic-viewport', variant: 'runtime' }) }) - it('classifies createDynamicViewportError as dynamic-viewport + navigation', () => { + it('classifies createDynamicViewportError as dynamic-viewport + dynamic', () => { expect( getBlockingRouteErrorDetails(createDynamicViewportError(ROUTE)) - ).toEqual({ type: 'dynamic-viewport', variant: 'navigation' }) + ).toEqual({ type: 'dynamic-viewport', variant: 'dynamic' }) }) - it('classifies createDynamicOrRuntimeViewportError as dynamic-viewport + navigation', () => { + it('classifies createDynamicOrRuntimeViewportError as dynamic-viewport + dynamic', () => { expect( getBlockingRouteErrorDetails(createDynamicOrRuntimeViewportError(ROUTE)) - ).toEqual({ type: 'dynamic-viewport', variant: 'navigation' }) + ).toEqual({ type: 'dynamic-viewport', variant: 'dynamic' }) }) it.each<[SyncIOApiType, string, string]>([ diff --git a/packages/next/src/next-devtools/dev-overlay/container/errors.tsx b/packages/next/src/next-devtools/dev-overlay/container/errors.tsx index c87316db391f..a0d19b6aeff2 100644 --- a/packages/next/src/next-devtools/dev-overlay/container/errors.tsx +++ b/packages/next/src/next-devtools/dev-overlay/container/errors.tsx @@ -28,6 +28,7 @@ import { type GuidanceKind, type GuidanceVariant, } from '../components/instant/instant-guidance' +import { BLOCKING_ROUTE_NAVIGATION_EXPLANATION } from '../components/instant/instant-guidance-data' import { CodeFrame } from '../components/code-frame/code-frame' import { ErrorOverlayCallStack } from '../components/errors/error-overlay-call-stack/error-overlay-call-stack' import { ErrorCause } from './runtime-error/error-cause' @@ -129,17 +130,18 @@ type HydrationErrorDetails = { type BlockingRouteErrorDetails = { type: 'blocking-route' - variant: 'navigation' | 'runtime' + variant: 'dynamic' | 'runtime' + inNavigation: boolean } type DynamicMetadataErrorDetails = { type: 'dynamic-metadata' - variant: 'navigation' | 'runtime' + variant: 'dynamic' | 'runtime' } type DynamicViewportErrorDetails = { type: 'dynamic-viewport' - variant: 'navigation' | 'runtime' + variant: 'dynamic' | 'runtime' } type SyncIOErrorDetails = { @@ -320,16 +322,31 @@ export function isSyncIOClientError(message: string): boolean { return match !== null && match[2] === '-client' } +// Detects errors emitted during navigation-phase instant validation: body +// errors from `createRuntimeBodyErrorInNavigation` / +// `createDynamicBodyErrorInNavigation` (SSR factories instead say "during +// the initial render"), and validation errors from +// `trackDynamicHoleInNavigation` / `getNavigationDisallowedDynamicReasons`. +export function isBlockingRouteInNavError(message: string): boolean { + return ( + message.includes('or a navigation') || + message.includes('Could not validate `unstable_instant`') || + message.includes('Could not validate instant UI') + ) +} + export function getBlockingRouteErrorDetails( error: Error ): null | ErrorDetails { const message = error.message + const inNavigation = isBlockingRouteInNavError(message) const isBlockingPageLoadError = message.includes('/blocking-route') if (isBlockingPageLoadError) { return { type: 'blocking-route', - variant: isRuntimeVariant(message) ? 'runtime' : 'navigation', + variant: isRuntimeVariant(message) ? 'runtime' : 'dynamic', + inNavigation, } } @@ -339,7 +356,7 @@ export function getBlockingRouteErrorDetails( if (isDynamicMetadataError) { return { type: 'dynamic-metadata', - variant: isRuntimeVariant(message) ? 'runtime' : 'navigation', + variant: isRuntimeVariant(message) ? 'runtime' : 'dynamic', } } @@ -349,7 +366,7 @@ export function getBlockingRouteErrorDetails( if (isBlockingViewportError) { return { type: 'dynamic-viewport', - variant: isRuntimeVariant(message) ? 'runtime' : 'navigation', + variant: isRuntimeVariant(message) ? 'runtime' : 'dynamic', } } @@ -540,10 +557,23 @@ Next.js version: ${props.versionInfo.installed} (${process.env.__NEXT_BUNDLER})\ errorType={errorType} errorMessage={ errorDetails.variant === 'runtime' - ? 'Next.js encountered runtime data during the initial render.' - : 'Next.js encountered uncached data during the initial render.' + ? errorDetails.inNavigation + ? 'Next.js encountered runtime data during a navigation.' + : 'Next.js encountered runtime data during the initial render.' + : errorDetails.inNavigation + ? 'Next.js encountered uncached data during a navigation.' + : 'Next.js encountered uncached data during the initial render.' + } + headerChildren={ + } - headerChildren={} onClose={isServerError ? undefined : onClose} debugInfo={debugInfo} error={error} diff --git a/packages/next/src/next-devtools/dev-overlay/dev-overlay.tsx b/packages/next/src/next-devtools/dev-overlay/dev-overlay.tsx index f0ac1350ffd8..ce5d42b13436 100644 --- a/packages/next/src/next-devtools/dev-overlay/dev-overlay.tsx +++ b/packages/next/src/next-devtools/dev-overlay/dev-overlay.tsx @@ -1,4 +1,4 @@ -import { createContext, useContext, useRef, useState } from 'react' +import { createContext, useContext, useEffect, useRef, useState } from 'react' import { ShadowPortal } from './components/shadow-portal' import { ComponentStyles } from './styles/component-styles' import { ErrorOverlay } from './components/errors/error-overlay/error-overlay' @@ -9,6 +9,7 @@ import { DevToolsIndicator } from './components/devtools-indicator/devtools-indi import { PanelRouter } from './menu/panel-router' import { PanelRouterContext, type PanelStateKind } from './menu/context' import { useDevOverlayContext } from '../dev-overlay.browser' +import { ACTION_INSTANT_ERRORS_CLEAR, type DispatcherEvent } from './shared' export const RenderErrorContext = createContext<{ runtimeErrors: ReadyRuntimeError[] @@ -17,6 +18,26 @@ export const RenderErrorContext = createContext<{ export const useRenderErrorContext = () => useContext(RenderErrorContext) +// Dispatches `ACTION_INSTANT_ERRORS_CLEAR` whenever the page changes to a +// new non-empty value. The first non-empty value is recorded as a baseline +// (the route the user landed on) and does not trigger a clear. +function useClearInstantErrorsOnNav( + page: string, + dispatch: (action: DispatcherEvent) => void +) { + const baselinePageRef = useRef(null) + useEffect(() => { + if (page === '') return + if (baselinePageRef.current === null) { + baselinePageRef.current = page + return + } + if (page === baselinePageRef.current) return + baselinePageRef.current = page + dispatch({ type: ACTION_INSTANT_ERRORS_CLEAR, currentPath: page }) + }, [page, dispatch]) +} + export function DevOverlay() { const [selectedIndex, setSelectedIndex] = useState(-1) const { state, dispatch, getSquashedHydrationErrorDetails } = @@ -25,6 +46,8 @@ export function DevOverlay() { state.instantNavs ? 'instant-navs' : null ) + useClearInstantErrorsOnNav(state.page, dispatch) + const triggerRef = useRef(null) return ( diff --git a/packages/next/src/next-devtools/dev-overlay/shared.test.ts b/packages/next/src/next-devtools/dev-overlay/shared.test.ts new file mode 100644 index 000000000000..2419ca596064 --- /dev/null +++ b/packages/next/src/next-devtools/dev-overlay/shared.test.ts @@ -0,0 +1,99 @@ +import { + createDynamicBodyError, + createDynamicBodyErrorInNavigation, + createRuntimeBodyError, + createRuntimeBodyErrorInNavigation, +} from '../../server/app-render/blocking-route-messages' +import { getInstantErrorRoute, routeTemplateMatchesPath } from './shared' + +const STATIC_ROUTE = '/example' +const DYNAMIC_ROUTE_TEMPLATE = '/posts/[slug]' +const CATCH_ALL_ROUTE_TEMPLATE = '/docs/[...slug]' + +describe('getInstantErrorRoute', () => { + it('returns the route for an in-navigation runtime body error', () => { + expect( + getInstantErrorRoute(createRuntimeBodyErrorInNavigation(STATIC_ROUTE)) + ).toBe(STATIC_ROUTE) + }) + + it('returns the route for an in-navigation dynamic body error', () => { + expect( + getInstantErrorRoute( + createDynamicBodyErrorInNavigation(DYNAMIC_ROUTE_TEMPLATE) + ) + ).toBe(DYNAMIC_ROUTE_TEMPLATE) + }) + + it('returns the route for the unrendered-segment wrapper', () => { + const error = new Error( + `Route "${STATIC_ROUTE}": Could not validate instant UI because an expected segment was not rendered.\n\nUnrendered segment:\n app/example/page.tsx` + ) + expect(getInstantErrorRoute(error)).toBe(STATIC_ROUTE) + }) + + it('returns null for SSR-only body errors', () => { + expect(getInstantErrorRoute(createRuntimeBodyError(STATIC_ROUTE))).toBe( + null + ) + expect(getInstantErrorRoute(createDynamicBodyError(STATIC_ROUTE))).toBe( + null + ) + }) + + it('returns null for unrelated errors', () => { + expect(getInstantErrorRoute(new Error('regular bug'))).toBe(null) + }) + + it('returns null for non-Error inputs', () => { + expect(getInstantErrorRoute(null)).toBe(null) + expect(getInstantErrorRoute(undefined)).toBe(null) + expect(getInstantErrorRoute('string error')).toBe(null) + }) +}) + +describe('routeTemplateMatchesPath', () => { + it('matches identical static routes', () => { + expect(routeTemplateMatchesPath(STATIC_ROUTE, STATIC_ROUTE)).toBe(true) + }) + + it('does not match different static routes', () => { + expect(routeTemplateMatchesPath('/foo', '/bar')).toBe(false) + }) + + it('matches a dynamic template against a resolved URL', () => { + expect(routeTemplateMatchesPath(DYNAMIC_ROUTE_TEMPLATE, '/posts/123')).toBe( + true + ) + expect( + routeTemplateMatchesPath(DYNAMIC_ROUTE_TEMPLATE, '/posts/hello-world') + ).toBe(true) + }) + + it('does not match a dynamic template against a sibling route', () => { + expect(routeTemplateMatchesPath(DYNAMIC_ROUTE_TEMPLATE, '/users/123')).toBe( + false + ) + }) + + it('does not match a dynamic template against deeper path segments', () => { + expect( + routeTemplateMatchesPath(DYNAMIC_ROUTE_TEMPLATE, '/posts/2026/05/16') + ).toBe(false) + }) + + it('matches a catch-all template against multiple resolved segments', () => { + expect( + routeTemplateMatchesPath( + CATCH_ALL_ROUTE_TEMPLATE, + '/docs/getting-started' + ) + ).toBe(true) + expect( + routeTemplateMatchesPath( + CATCH_ALL_ROUTE_TEMPLATE, + '/docs/app/api-reference/functions/cookies' + ) + ).toBe(true) + }) +}) diff --git a/packages/next/src/next-devtools/dev-overlay/shared.ts b/packages/next/src/next-devtools/dev-overlay/shared.ts index 1d726d9c6041..0db34096c6dd 100644 --- a/packages/next/src/next-devtools/dev-overlay/shared.ts +++ b/packages/next/src/next-devtools/dev-overlay/shared.ts @@ -9,6 +9,9 @@ import { parseStack } from '../../server/lib/parse-stack' import { isConsoleError } from '../shared/console-error' import type { CacheIndicatorState } from './cache-indicator' import { readInstantNavCookieState } from './components/instant-navs/instant-nav-cookie' +import { isBlockingRouteInNavError } from './container/errors' +import { isDynamicRoute } from '../../shared/lib/router/utils/is-dynamic' +import { getRouteRegex } from '../../shared/lib/router/utils/route-regex' export type DevToolsConfig = { theme?: 'light' | 'dark' | 'system' @@ -107,6 +110,7 @@ export const ACTION_DEVTOOLS_SCALE = 'devtools-scale' export const ACTION_DEVTOOLS_CONFIG = 'devtools-config' export const ACTION_INSTANT_NAVS_TOGGLE = 'instant-navs-toggle' export const ACTION_INSTANT_NAVS_RESET = 'instant-navs-reset' +export const ACTION_INSTANT_ERRORS_CLEAR = 'instant-errors-clear' export const STORAGE_KEY_PANEL_POSITION_PREFIX = '__nextjs-dev-tools-panel-position' @@ -231,6 +235,11 @@ interface InstantNavResetAction { type: typeof ACTION_INSTANT_NAVS_RESET } +interface InstantErrorsClearAction { + type: typeof ACTION_INSTANT_ERRORS_CLEAR + currentPath: string +} + export type DispatcherEvent = | BuildOkAction | BuildErrorAction @@ -258,6 +267,7 @@ export type DispatcherEvent = | DevToolsConfigAction | CacheOnlyToggleAction | InstantNavResetAction + | InstantErrorsClearAction const REACT_ERROR_STACK_BOTTOM_FRAME_REGEX = // 1st group: new frame + v8 @@ -274,6 +284,33 @@ function getStackIgnoringStrictMode(stack: string | undefined) { return stack?.split(REACT_ERROR_STACK_BOTTOM_FRAME_REGEX)[0] } +export function getInstantErrorRoute(error: unknown): string | null { + if (!error || typeof error !== 'object') return null + const message = (error as Error).message + if (typeof message !== 'string') return null + if (!isBlockingRouteInNavError(message)) return null + // Most factories prefix `Route "":`; the missing-segment factory in + // `dynamic-rendering.ts` writes `Route: ` on its own line in the body. + const prefixMatch = /^Route "([^"]+)":/.exec(message) + if (prefixMatch) return prefixMatch[1] + const lineMatch = /\nRoute: (\S+)/.exec(message) + return lineMatch ? lineMatch[1] : null +} + +// The route stored on an instant error is the route *template* from +// `workStore.route` (e.g. `/foo/[slug]`), but the page we track in dev +// overlay state is the resolved URL (e.g. `/foo/123`). For dynamic routes +// we compile the template to a regex so the clear-on-nav reducer keeps +// errors whose template matches the page the user just landed on. +export function routeTemplateMatchesPath( + template: string, + path: string +): boolean { + if (template === path) return true + if (!isDynamicRoute(template)) return false + return getRouteRegex(template).re.test(path) +} + const shouldDisableDevIndicator = process.env.__NEXT_DEV_INDICATOR?.toString() === 'false' @@ -539,6 +576,17 @@ export function useErrorOverlayReducer( case ACTION_INSTANT_NAVS_RESET: { return { ...state, instantNavs: false } } + case ACTION_INSTANT_ERRORS_CLEAR: { + const remaining = state.errors.filter((event) => { + const route = getInstantErrorRoute(event.error) + if (route === null) return true + return routeTemplateMatchesPath(route, action.currentPath) + }) + if (remaining.length === state.errors.length) { + return state + } + return { ...state, errors: remaining } + } default: { return state } diff --git a/packages/next/src/server/app-render/blocking-route-messages.ts b/packages/next/src/server/app-render/blocking-route-messages.ts index cb1de77cb370..84801cc7a1d0 100644 --- a/packages/next/src/server/app-render/blocking-route-messages.ts +++ b/packages/next/src/server/app-render/blocking-route-messages.ts @@ -22,6 +22,30 @@ export function createDynamicBodyError(route: string): Error { ) } +export function createRuntimeBodyErrorInNavigation(route: string): Error { + return new Error( + `Route "${route}": Next.js encountered runtime data during the initial render or a navigation.\n\n` + + `\`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\n\n` + + `Ways to fix this:\n` + + ` - Provide a placeholder with \`\` around the data access\n` + + ` - Use \`generateStaticParams\` to make route params static\n` + + ` - Set \`export const instant = false\` to allow a blocking route\n\n` + + `Learn more: https://nextjs.org/docs/messages/blocking-route` + ) +} + +export function createDynamicBodyErrorInNavigation(route: string): Error { + return new Error( + `Route "${route}": Next.js encountered uncached data during the initial render or a navigation.\n\n` + + `\`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience.\n\n` + + `Ways to fix this:\n` + + ` - Cache the data access with \`"use cache"\`\n` + + ` - Provide a placeholder with \`\` around the data access\n` + + ` - Set \`export const instant = false\` to allow a blocking route\n\n` + + `Learn more: https://nextjs.org/docs/messages/blocking-route` + ) +} + /** * NOTE: Prefer `createRuntimeBodyError` or `createDynamicBodyError`. * Only use this in situations like build-time static validation, where diff --git a/packages/next/src/server/app-render/dynamic-rendering.ts b/packages/next/src/server/app-render/dynamic-rendering.ts index 5fb7bbbdeb2b..e8c699614460 100644 --- a/packages/next/src/server/app-render/dynamic-rendering.ts +++ b/packages/next/src/server/app-render/dynamic-rendering.ts @@ -50,6 +50,8 @@ import { BailoutToCSRError } from '../../shared/lib/lazy-dynamic/bailout-to-csr' import { createRuntimeBodyError, createDynamicBodyError, + createRuntimeBodyErrorInNavigation, + createDynamicBodyErrorInNavigation, createDynamicOrRuntimeBodyError, createRuntimeMetadataError, createDynamicMetadataError, @@ -1026,8 +1028,8 @@ export function trackDynamicHoleInNavigation( const error = addErrorContext( kind === DynamicHoleKind.Runtime - ? createRuntimeBodyError(workStore.route) - : createDynamicBodyError(workStore.route), + ? createRuntimeBodyErrorInNavigation(workStore.route) + : createDynamicBodyErrorInNavigation(workStore.route), componentStack, effectiveCreateInstantStack ) diff --git a/test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts b/test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts index b776555f0046..13f2f996118a 100644 --- a/test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts +++ b/test/e2e/app-dir/instant-validation-build/instant-validation-build.test.ts @@ -63,9 +63,9 @@ describe('instant-validation-build', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/invalid-missing-suspense-around-runtime": Next.js encountered uncached data during the initial render. + "Error: Route "/invalid-missing-suspense-around-runtime": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` diff --git a/test/e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts b/test/e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts index d79b24574e98..1a9eb517f614 100644 --- a/test/e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts +++ b/test/e2e/app-dir/instant-validation-causes/instant-validation-causes.test.ts @@ -105,8 +105,8 @@ describe('instant validation causes', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/named-export/page.tsx (7:16) @ Page @@ -136,8 +136,8 @@ describe('instant validation causes', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/aliased-export/page.tsx (7:16) @ Page @@ -167,8 +167,8 @@ describe('instant validation causes', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/reexport/page.tsx (6:16) @ Page @@ -201,8 +201,8 @@ describe('instant validation causes', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/indirect-export/page.tsx (8:16) @ Page diff --git a/test/e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts b/test/e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts index 84417eae91f7..ac346f83eb96 100644 --- a/test/e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts +++ b/test/e2e/app-dir/instant-validation-level-error/instant-validation-level-error.test.ts @@ -60,8 +60,8 @@ describe('instant validation - level error', () => { const browser = await next.browser('/bare') await expect(browser).toDisplayCollapsedRedbox(` { - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/bare/page.tsx (11:19) @ Page @@ -90,8 +90,8 @@ describe('instant validation - level error', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-error/page.tsx (11:19) @ Page @@ -120,8 +120,8 @@ describe('instant validation - level error', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-true/page.tsx (12:19) @ Page @@ -150,8 +150,8 @@ describe('instant validation - level error', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-warning/page.tsx (11:19) @ Page @@ -177,8 +177,8 @@ describe('instant validation - level error', () => { const browser = await next.browser('/layered') await expect(browser).toDisplayCollapsedRedbox(` { - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/layered/page.tsx (8:19) @ Page @@ -197,9 +197,9 @@ describe('instant validation - level error', () => { const result = await prerender('/bare') expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/bare": Next.js encountered uncached data during the initial render. + "Error: Route "/bare": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -223,9 +223,9 @@ describe('instant validation - level error', () => { const result = await prerender('/explicit-error') expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/explicit-error": Next.js encountered uncached data during the initial render. + "Error: Route "/explicit-error": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -249,9 +249,9 @@ describe('instant validation - level error', () => { const result = await prerender('/explicit-true') expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/explicit-true": Next.js encountered uncached data during the initial render. + "Error: Route "/explicit-true": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -288,9 +288,9 @@ describe('instant validation - level error', () => { const result = await prerender('/layered') expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/layered": Next.js encountered uncached data during the initial render. + "Error: Route "/layered": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` diff --git a/test/e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts b/test/e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts index 1b78c6d380b2..74f9e9fdb444 100644 --- a/test/e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts +++ b/test/e2e/app-dir/instant-validation-level-manual-error/instant-validation-level-manual-error.test.ts @@ -79,8 +79,8 @@ describe('instant validation - level manual-error', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-error/page.tsx (11:19) @ Page @@ -109,8 +109,8 @@ describe('instant validation - level manual-error', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-true/page.tsx (12:19) @ Page @@ -139,8 +139,8 @@ describe('instant validation - level manual-error', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-warning/page.tsx (11:19) @ Page @@ -180,9 +180,9 @@ describe('instant validation - level manual-error', () => { const result = await prerender('/explicit-error') expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/explicit-error": Next.js encountered uncached data during the initial render. + "Error: Route "/explicit-error": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -206,9 +206,9 @@ describe('instant validation - level manual-error', () => { const result = await prerender('/explicit-true') expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/explicit-true": Next.js encountered uncached data during the initial render. + "Error: Route "/explicit-true": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` diff --git a/test/e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts b/test/e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts index 3f0e9e88a20f..7ca9596bed3a 100644 --- a/test/e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts +++ b/test/e2e/app-dir/instant-validation-level-manual-warning/instant-validation-level-manual-warning.test.ts @@ -93,8 +93,8 @@ describe('instant validation - level manual-warning', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "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 @@ -125,8 +125,8 @@ describe('instant validation - level manual-warning', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "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 @@ -157,8 +157,8 @@ describe('instant validation - level manual-warning', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "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 @@ -192,9 +192,9 @@ describe('instant validation - level manual-warning', () => { const result = await prerender('/with-root-suspense/explicit-error') expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/with-root-suspense/explicit-error": Next.js encountered uncached data during the initial render. + "Error: Route "/with-root-suspense/explicit-error": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` diff --git a/test/e2e/app-dir/instant-validation-level-warning/instant-validation-level-warning.test.ts b/test/e2e/app-dir/instant-validation-level-warning/instant-validation-level-warning.test.ts index f5cbb87854cf..d3db682bad6a 100644 --- a/test/e2e/app-dir/instant-validation-level-warning/instant-validation-level-warning.test.ts +++ b/test/e2e/app-dir/instant-validation-level-warning/instant-validation-level-warning.test.ts @@ -60,8 +60,8 @@ describe('instant validation - level warning', () => { const browser = await next.browser('/bare') await expect(browser).toDisplayCollapsedRedbox(` { - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/bare/page.tsx (10:19) @ Page @@ -90,8 +90,8 @@ describe('instant validation - level warning', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-error/page.tsx (10:19) @ Page @@ -120,8 +120,8 @@ describe('instant validation - level warning', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-true/page.tsx (11:19) @ Page @@ -150,8 +150,8 @@ describe('instant validation - level warning', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/explicit-warning/page.tsx (11:19) @ Page @@ -177,8 +177,8 @@ describe('instant validation - level warning', () => { const browser = await next.browser('/layered') await expect(browser).toDisplayCollapsedRedbox(` { - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/layered/page.tsx (8:19) @ Page @@ -202,9 +202,9 @@ describe('instant validation - level warning', () => { const result = await prerender('/explicit-error') expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/explicit-error": Next.js encountered uncached data during the initial render. + "Error: Route "/explicit-error": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` diff --git a/test/e2e/app-dir/instant-validation/instant-validation-parallel-slots.test.ts b/test/e2e/app-dir/instant-validation/instant-validation-parallel-slots.test.ts index 9fb825531120..cefa1e09041c 100644 --- a/test/e2e/app-dir/instant-validation/instant-validation-parallel-slots.test.ts +++ b/test/e2e/app-dir/instant-validation/instant-validation-parallel-slots.test.ts @@ -124,8 +124,8 @@ describe('instant validation - parallel slot configs', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/parallel/slot-config-only/page.tsx (4:16) @ ChildrenPage @@ -142,9 +142,9 @@ describe('instant validation - parallel slot configs', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/parallel/slot-config-only": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/parallel/slot-config-only": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -184,8 +184,8 @@ describe('instant validation - parallel slot configs', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/parallel/slot-layout-config/page.tsx (4:16) @ ChildrenPage @@ -202,9 +202,9 @@ describe('instant validation - parallel slot configs', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/parallel/slot-layout-config": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/parallel/slot-layout-config": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -244,8 +244,8 @@ describe('instant validation - parallel slot configs', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/parallel/slot-runtime-config/page.tsx (4:16) @ ChildrenPage @@ -262,9 +262,9 @@ describe('instant validation - parallel slot configs', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/parallel/slot-runtime-config": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/parallel/slot-runtime-config": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -306,8 +306,8 @@ describe('instant validation - parallel slot configs', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/parallel/children-config-with-slot/@slot/page.tsx (4:16) @ SlotPage @@ -324,9 +324,9 @@ describe('instant validation - parallel slot configs', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/parallel/children-config-with-slot": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/parallel/children-config-with-slot": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -368,8 +368,8 @@ describe('instant validation - parallel slot configs', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/parallel/fork-layout-config-with-slot/@slot/page.tsx (4:16) @ SlotPage @@ -392,8 +392,8 @@ describe('instant validation - parallel slot configs', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/parallel/fork-layout-config-with-slot/page.tsx (4:16) @ ChildrenPage @@ -411,9 +411,9 @@ describe('instant validation - parallel slot configs', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/parallel/fork-layout-config-with-slot": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/parallel/fork-layout-config-with-slot": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -425,9 +425,9 @@ describe('instant validation - parallel slot configs', () => { at body () at html () at a () - Error: Route "/suspense-in-root/parallel/fork-layout-config-with-slot": Next.js encountered runtime data during the initial render. + Error: Route "/suspense-in-root/parallel/fork-layout-config-with-slot": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -535,8 +535,8 @@ describe('instant validation - parallel slot configs', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/parallel/conditional-breadcrumbs/show-both/@breadcrumbs/blocked/page.tsx (3:16) @ BreadcrumbsPage @@ -551,9 +551,9 @@ describe('instant validation - parallel slot configs', () => { const result = await prerender(href) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/parallel/conditional-breadcrumbs/show-both/blocked": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/parallel/conditional-breadcrumbs/show-both/blocked": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -583,7 +583,7 @@ describe('instant validation - parallel slot configs', () => { const browser = await navigateTo(href) await expect(browser).toDisplayCollapsedRedbox(` { - "code": "E1246", + "code": "E1248", "description": "Could not validate instant UI because an expected segment was not rendered. Unrendered segment: @@ -650,8 +650,8 @@ describe('instant validation - parallel slot configs', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/parallel/conditional-breadcrumbs/show-only-breadcrumbs/@breadcrumbs/blocked/page.tsx (3:16) @ BreadcrumbsPage @@ -666,9 +666,9 @@ describe('instant validation - parallel slot configs', () => { const result = await prerender(href) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/parallel/conditional-breadcrumbs/show-only-breadcrumbs/blocked": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/parallel/conditional-breadcrumbs/show-only-breadcrumbs/blocked": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access diff --git a/test/e2e/app-dir/instant-validation/instant-validation.test.ts b/test/e2e/app-dir/instant-validation/instant-validation.test.ts index d155428d591b..9b3def2e15e1 100644 --- a/test/e2e/app-dir/instant-validation/instant-validation.test.ts +++ b/test/e2e/app-dir/instant-validation/instant-validation.test.ts @@ -180,8 +180,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/missing-suspense-around-runtime/page.tsx (6:16) @ Page @@ -198,9 +198,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/missing-suspense-around-runtime": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/missing-suspense-around-runtime": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -240,8 +240,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/missing-suspense-around-dynamic/page.tsx (6:19) @ Page @@ -258,9 +258,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/missing-suspense-around-dynamic": Next.js encountered uncached data during the initial render. + "Error: Route "/suspense-in-root/static/missing-suspense-around-dynamic": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -300,8 +300,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/runtime/missing-suspense-around-dynamic/page.tsx (23:19) @ Dynamic @@ -319,9 +319,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/runtime/missing-suspense-around-dynamic": Next.js encountered uncached data during the initial render. + "Error: Route "/suspense-in-root/runtime/missing-suspense-around-dynamic": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -363,8 +363,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/missing-suspense-around-dynamic-layout/layout.tsx (7:16) @ Layout @@ -381,9 +381,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/missing-suspense-around-dynamic-layout": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/missing-suspense-around-dynamic-layout": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -423,8 +423,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/runtime/missing-suspense-around-dynamic-layout/layout.tsx (8:19) @ Layout @@ -441,9 +441,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/runtime/missing-suspense-around-dynamic-layout": Next.js encountered uncached data during the initial render. + "Error: Route "/suspense-in-root/runtime/missing-suspense-around-dynamic-layout": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -486,8 +486,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/missing-suspense-around-params/[param]/page.tsx (20:21) @ Runtime @@ -534,8 +534,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/missing-suspense-around-search-params/page.tsx (7:18) @ Page @@ -552,9 +552,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/missing-suspense-around-search-params": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/missing-suspense-around-search-params": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -629,8 +629,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/suspense-too-high/page.tsx (6:16) @ Page @@ -647,9 +647,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/suspense-too-high": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/suspense-too-high": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -692,8 +692,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/runtime/suspense-too-high/page.tsx (24:19) @ Dynamic @@ -711,9 +711,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/runtime/suspense-too-high": Next.js encountered uncached data during the initial render. + "Error: Route "/suspense-in-root/runtime/suspense-too-high": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -1231,8 +1231,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/invalid-loading-above-route-group/(group)/page.tsx (34:19) @ Dynamic @@ -1250,9 +1250,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/invalid-loading-above-route-group": Next.js encountered uncached data during the initial render. + "Error: Route "/suspense-in-root/static/invalid-loading-above-route-group": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -1295,8 +1295,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/invalid-dynamic-layout-with-loading/layout.tsx (24:19) @ Dynamic @@ -1314,9 +1314,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/invalid-dynamic-layout-with-loading": Next.js encountered uncached data during the initial render. + "Error: Route "/suspense-in-root/static/invalid-dynamic-layout-with-loading": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -1372,8 +1372,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/blocking-layout/missing-suspense-around-dynamic/page.tsx (6:16) @ Page @@ -1390,9 +1390,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/blocking-layout/missing-suspense-around-dynamic": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/blocking-layout/missing-suspense-around-dynamic": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -1460,8 +1460,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/invalid-blocking-inside-static/page.tsx (6:16) @ BlockingPage @@ -1478,9 +1478,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/invalid-blocking-inside-static": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/invalid-blocking-inside-static": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -1521,8 +1521,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/runtime/invalid-blocking-inside-runtime/page.tsx (6:19) @ BlockingPage @@ -1539,9 +1539,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/runtime/invalid-blocking-inside-runtime": Next.js encountered uncached data during the initial render. + "Error: Route "/suspense-in-root/runtime/invalid-blocking-inside-runtime": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -1585,8 +1585,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/missing-suspense-in-parallel-route/@slot/page.tsx (4:16) @ IndexSlot @@ -1603,9 +1603,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/missing-suspense-in-parallel-route": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/missing-suspense-in-parallel-route": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -1647,8 +1647,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/missing-suspense-in-parallel-route/@slot/foo/page.tsx (4:16) @ FooSlot @@ -1665,9 +1665,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/missing-suspense-in-parallel-route/foo": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/missing-suspense-in-parallel-route/foo": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -1709,8 +1709,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/missing-suspense-in-parallel-route/@slot/default.tsx (4:16) @ DefaultSlot @@ -1727,9 +1727,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/missing-suspense-in-parallel-route/bar": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/missing-suspense-in-parallel-route/bar": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -2580,8 +2580,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/route-group-config-only/(group)/page.tsx (4:16) @ Page @@ -2598,9 +2598,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/route-group-config-only": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/route-group-config-only": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -2641,8 +2641,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/route-group-config-and-segment-config/(group)/page.tsx (4:16) @ Page @@ -2659,9 +2659,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/route-group-config-and-segment-config": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/route-group-config-and-segment-config": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -2703,8 +2703,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/route-group-segment-config-only/(group)/page.tsx (4:16) @ Page @@ -2721,9 +2721,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/route-group-segment-config-only": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/route-group-segment-config-only": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -2765,8 +2765,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/route-group-config-with-deeper-segment/(group)/inner/page.tsx (4:16) @ Page @@ -2783,9 +2783,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/route-group-config-with-deeper-segment/inner": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/route-group-config-with-deeper-segment/inner": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -2827,8 +2827,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/route-group-deeper-segment-config/(group)/inner/page.tsx (4:16) @ Page @@ -2845,9 +2845,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/route-group-deeper-segment-config/inner": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/route-group-deeper-segment-config/inner": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -2896,8 +2896,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/route-group-shared-boundary/(outer)/(inner)/layout.tsx (13:16) @ InnerLayout @@ -2914,9 +2914,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/route-group-shared-boundary": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/route-group-shared-boundary": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -2972,8 +2972,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/parallel-group-depths-deep-slot-hole/@slot/(g1)/(g2)/(g3)/layout.tsx (7:16) @ G3Layout @@ -2990,9 +2990,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/parallel-group-depths-deep-slot-hole": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/parallel-group-depths-deep-slot-hole": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -3042,8 +3042,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/parallel-group-depths-shallow-slot-hole/(b1)/(b2)/layout.tsx (5:16) @ B2Layout @@ -3060,9 +3060,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/parallel-group-depths-shallow-slot-hole": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/parallel-group-depths-shallow-slot-hole": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -3113,8 +3113,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/runtime/static-layout-above-runtime-config/layout.tsx (15:16) @ StaticLayout @@ -3131,9 +3131,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/runtime/static-layout-above-runtime-config/inner": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/runtime/static-layout-above-runtime-config/inner": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -3181,8 +3181,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/config-depth-preference/@slot/[...catchall]/page.tsx (8:16) @ CatchallSlotPage @@ -3232,8 +3232,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/config-depth-preference-slot-wins/@slot/[...catchall]/page.tsx (7:16) @ CatchallSlotPage @@ -3250,9 +3250,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/config-depth-preference-slot-wins/deeper/[...rest]": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/config-depth-preference-slot-wins/deeper/[...rest]": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -3296,8 +3296,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/config-children-preferred/@slot/page.tsx (7:16) @ SlotPage @@ -3314,9 +3314,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/static/config-children-preferred": Next.js encountered runtime data during the initial render. + "Error: Route "/suspense-in-root/static/config-children-preferred": Next.js encountered runtime data during the initial render or a navigation. - \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`cookies()\`, \`headers()\`, \`params\`, or \`searchParams\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Provide a placeholder with \`\` around the data access @@ -3361,8 +3361,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1221", - "description": "Next.js encountered runtime data during the initial render.", + "code": "E1251", + "description": "Next.js encountered runtime data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/static/cross-slot-blocking/@slot/[...catchall]/page.tsx (8:16) @ CatchallSlotPage @@ -3412,7 +3412,7 @@ describe('instant validation', () => { ) await expect(browser).toDisplayCollapsedRedbox(` { - "code": "E1246", + "code": "E1248", "description": "Could not validate instant UI because an expected segment was not rendered. Unrendered segment: @@ -3476,7 +3476,7 @@ describe('instant validation', () => { ) await expect(browser).toDisplayCollapsedRedbox(` { - "code": "E1246", + "code": "E1248", "description": "Could not validate instant UI because an expected segment was not rendered. Unrendered segment: @@ -3538,7 +3538,7 @@ describe('instant validation', () => { ) await expect(browser).toDisplayCollapsedRedbox(` { - "code": "E1246", + "code": "E1248", "description": "Could not validate instant UI because an expected segment was not rendered. Unrendered segments: @@ -3646,9 +3646,9 @@ describe('instant validation', () => { ) expect(extractBuildValidationError(result.cliOutput)) .toMatchInlineSnapshot(` - "Error: Route "/suspense-in-root/disable-validation/disable-dev": Next.js encountered uncached data during the initial render. + "Error: Route "/suspense-in-root/disable-validation/disable-dev": Next.js encountered uncached data during the initial render or a navigation. - \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered, blocking navigation and leading to a slower user experience. + \`fetch(...)\` or \`connection()\` accessed outside of \`\` prevents the route from being prerendered or the navigation from being instant, leading to a slower user experience. Ways to fix this: - Cache the data access with \`"use cache"\` @@ -3688,8 +3688,8 @@ describe('instant validation', () => { ], }, ], - "code": "E1220", - "description": "Next.js encountered uncached data during the initial render.", + "code": "E1249", + "description": "Next.js encountered uncached data during a navigation.", "environmentLabel": "Server", "label": "Instant", "source": "app/suspense-in-root/disable-validation/disable-build/page.tsx (9:19) @ Page From 0114ea245c0df33fbf42bec74add063a717ae926 Mon Sep 17 00:00:00 2001 From: Luke Sandberg Date: Mon, 18 May 2026 11:58:37 -0700 Subject: [PATCH 3/3] Eval next.config export functions in the try catch (#93884) Move next.config evaluation inside the try catch where we import and transform it This ensures we print an appropriate help link if the export function throws --- packages/next/src/server/config.ts | 20 ++++-- .../config-evaluation-error.test.ts | 68 +++++++++++++++++++ .../config-evaluation-error/pages/index.js | 3 + 3 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 test/production/config-evaluation-error/config-evaluation-error.test.ts create mode 100644 test/production/config-evaluation-error/pages/index.js diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 36af419df631..2c4827f7abdd 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -1805,6 +1805,7 @@ export default async function loadConfig( configFileName = basename(path) let userConfigModule: any + let loadedConfig: NextConfig try { const envBefore = Object.assign({}, process.env) @@ -1845,6 +1846,18 @@ export default async function loadConfig( return userConfigModule } + + // `normalizeConfig` invokes the user's exported config function (or + // awaits its returned promise) if it is one. Errors thrown from that + // call belong to the same "failed to load config" category as parse + // errors from `import()` above, so we keep them inside this try/catch + // to attach the same framing message. + loadedConfig = Object.freeze( + (await normalizeConfig( + phase, + interopDefault(userConfigModule) + )) as NextConfig + ) } catch (err) { // Capture the error for MCP tool reporting NextInstanceErrorState.nextConfig.push(err) @@ -1856,13 +1869,6 @@ export default async function loadConfig( throw err } - const loadedConfig = Object.freeze( - (await normalizeConfig( - phase, - interopDefault(userConfigModule) - )) as NextConfig - ) - if (loadedConfig.experimental) { for (const name of Object.keys( loadedConfig.experimental diff --git a/test/production/config-evaluation-error/config-evaluation-error.test.ts b/test/production/config-evaluation-error/config-evaluation-error.test.ts new file mode 100644 index 000000000000..57a78e74d2cd --- /dev/null +++ b/test/production/config-evaluation-error/config-evaluation-error.test.ts @@ -0,0 +1,68 @@ +import { nextTestSetup } from 'e2e-utils' + +describe('next.config evaluation error', () => { + describe('production mode', () => { + const { next, skipped } = nextTestSetup({ + files: __dirname, + skipStart: true, + skipDeployment: true, + }) + if (skipped) return + + async function buildAndGetOutput(): Promise { + const start = next.cliOutput.length + await next.build() + return next.cliOutput.slice(start) + } + + it('should report a helpful error when the config function throws synchronously', async () => { + await next.patchFile( + 'next.config.js', + ` + module.exports = () => { + return { foo: new Uint8Array(5_000_000_000) } + } + ` + ) + const output = await buildAndGetOutput() + + expect(output).toContain('Invalid typed array length') + expect(output).toContain( + 'Failed to load next.config.js, see more info here https://nextjs.org/docs/messages/next-config-error' + ) + }) + + it('should report a helpful error when the config module throws at the top level', async () => { + await next.patchFile( + 'next.config.js', + ` + const buf = new Uint8Array(5_000_000_000) + module.exports = { foo: buf } + ` + ) + const output = await buildAndGetOutput() + + expect(output).toContain('Invalid typed array length') + expect(output).toContain( + 'Failed to load next.config.js, see more info here https://nextjs.org/docs/messages/next-config-error' + ) + }) + + it('should report a helpful error when the config function rejects', async () => { + await next.patchFile( + 'next.config.js', + ` + module.exports = async () => { + throw new Error('boom from async config plugin') + } + ` + ) + const output = await buildAndGetOutput() + + expect(output).toContain('boom from async config plugin') + expect(output).toContain( + 'Failed to load next.config.js, see more info here https://nextjs.org/docs/messages/next-config-error' + ) + }) + }) +}) diff --git a/test/production/config-evaluation-error/pages/index.js b/test/production/config-evaluation-error/pages/index.js new file mode 100644 index 000000000000..821fdd14d097 --- /dev/null +++ b/test/production/config-evaluation-error/pages/index.js @@ -0,0 +1,3 @@ +export default function Page(props) { + return

index page

+}