From 27a1d30986cca01c976b80f2c7eaf7a5364b52e0 Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Mon, 1 Jun 2026 13:45:21 +0200
Subject: [PATCH 1/6] errors: centralize and DX-friendly use cache error
messages
---
packages/next/errors.json | 22 +-
.../container/runtime-error/error-cause.tsx | 3 +-
.../next/src/server/request/connection.ts | 17 +-
packages/next/src/server/request/cookies.ts | 12 +-
.../next/src/server/request/draft-mode.ts | 14 +-
packages/next/src/server/request/headers.ts | 12 +-
packages/next/src/server/request/utils.ts | 5 +-
.../server/route-modules/app-route/module.ts | 13 +-
.../next/src/server/use-cache/cache-life.ts | 5 +-
.../next/src/server/use-cache/cache-tag.ts | 5 +-
.../server/use-cache/use-cache-messages.ts | 195 ++++++++++++++++++
.../src/server/use-cache/use-cache-wrapper.ts | 38 +---
.../server/web/spec-extension/revalidate.ts | 12 +-
13 files changed, 277 insertions(+), 76 deletions(-)
create mode 100644 packages/next/src/server/use-cache/use-cache-messages.ts
diff --git a/packages/next/errors.json b/packages/next/errors.json
index baf7c33e5175..d008b7c059d7 100644
--- a/packages/next/errors.json
+++ b/packages/next/errors.json
@@ -1284,5 +1284,25 @@
"1283": "Cache Components error recovery expected an original Flight prerender result",
"1284": "Cache Components error recovery expected an original prerender store",
"1285": "Cache Components error recovery expected an original resume data cache",
- "1286": "Route \"%s\": Could not validate that a segment in your UI has instant navigation."
+ "1286": "Route \"%s\": Could not validate that a segment in your UI has instant navigation.",
+ "1287": "\\`cacheLife()\\` can only be called inside a \\`\"use cache\"\\` function.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/cacheLife",
+ "1288": "\\`\"use cache: private\"\\` needs an active request. It can't be used during \\`generateStaticParams\\` or other build-time contexts.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
+ "1289": "Route \"%s\": \\`searchParams\\` can't be read inside \\`\"use cache\"\\`. Await it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1290": "Route \"%s\": \\`cookies()\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1291": "\\`cacheTag()\\` can only be called inside a \\`\"use cache\"\\` function.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/cacheTag",
+ "1292": "Route \"%s\": \\`headers()\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1293": "\\`\"use cache: private\"\\` can't be nested inside \\`\"use cache\"\\`. It can only be nested inside another \\`\"use cache: private\"\\`.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
+ "1294": "Route \"%s\": \\`%s\\` can't be called inside \\`\"use cache\"\\`. Revalidation must run outside renders and cached functions so caches stay consistent.\\nLearn more: https://nextjs.org/docs/app/getting-started/revalidating",
+ "1295": "\\`\"use cache: private\"\\` can't be used inside \\`unstable_cache()\\`.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
+ "1296": "Route \"%s\": \\`%s\\` can't be called inside \\`unstable_cache()\\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1297": "Route \"%s\": \\`%s\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1298": "Route \"%s\": \\`cookies()\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1299": "Route \"%s\": \\`%s\\` can't be called inside \\`unstable_cache()\\`. Revalidation must run outside renders and cached functions so caches stay consistent.\\nLearn more: https://nextjs.org/docs/app/getting-started/revalidating",
+ "1300": "Route \"%s\": \\`connection()\\` can't be used inside \\`unstable_cache()\\`. A cache entry can be built before any request exists, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1301": "Route \"%s\": \\`%s\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1302": "Route \"%s\": \\`%s\\` can't be called inside \\`\"use cache\"\\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1303": "Route \"%s\": \\`headers()\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1304": "Route \"%s\": \\`connection()\\` can't be used inside \\`\"use cache: private\"\\`. A private cache entry can be built before a navigation request, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1305": "Route \"%s\": \\`connection()\\` can't be used inside \\`\"use cache\"\\`. A cache entry can be built before any request exists, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1306": "This \"use cache\" has a dynamic cache life that was propagated to its parent.\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife"
}
diff --git a/packages/next/src/next-devtools/dev-overlay/container/runtime-error/error-cause.tsx b/packages/next/src/next-devtools/dev-overlay/container/runtime-error/error-cause.tsx
index 81a733fd5c8a..6c32c853cc25 100644
--- a/packages/next/src/next-devtools/dev-overlay/container/runtime-error/error-cause.tsx
+++ b/packages/next/src/next-devtools/dev-overlay/container/runtime-error/error-cause.tsx
@@ -92,8 +92,7 @@ export const styles = `
}
.error-cause-message {
- margin: 0;
- margin-left: 4px;
+ margin: 0 0 16px 4px;
color: var(--color-red-900);
font-weight: 500;
font-size: var(--size-16);
diff --git a/packages/next/src/server/request/connection.ts b/packages/next/src/server/request/connection.ts
index 88e9e13c8a23..51d3f25c4632 100644
--- a/packages/next/src/server/request/connection.ts
+++ b/packages/next/src/server/request/connection.ts
@@ -17,6 +17,11 @@ import { isRequestAPICallableInsideAfter } from './utils'
import { applyOwnerStack } from '../dynamic-rendering-utils'
import { RenderStage } from '../app-render/staged-rendering'
import { InvariantError } from '../../shared/lib/invariant-error'
+import {
+ createConnectionInPublicUseCacheError,
+ createConnectionInPrivateUseCacheError,
+ createConnectionInUnstableCacheError,
+} from '../use-cache/use-cache-messages'
/**
* This function allows you to indicate that you require an actual user Request before continuing.
@@ -54,9 +59,7 @@ export function connection(): Promise {
if (workUnitStore) {
switch (workUnitStore.type) {
case 'cache': {
- const error = new Error(
- `Route ${workStore.route} used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`
- )
+ const error = createConnectionInPublicUseCacheError(workStore.route)
Error.captureStackTrace(error, connection)
applyOwnerStack(error)
workStore.invalidDynamicUsageError ??= error
@@ -66,18 +69,14 @@ export function connection(): Promise {
// It might not be intuitive to throw for private caches as well, but
// we don't consider runtime prefetches as "actual requests" (in the
// navigation sense), despite allowing them to read cookies.
- const error = new Error(
- `Route ${workStore.route} used \`connection()\` inside "use cache: private". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual navigation request, but caches must be able to be produced before a navigation request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`
- )
+ const error = createConnectionInPrivateUseCacheError(workStore.route)
Error.captureStackTrace(error, connection)
applyOwnerStack(error)
workStore.invalidDynamicUsageError ??= error
throw error
}
case 'unstable-cache':
- throw new Error(
- `Route ${workStore.route} used \`connection()\` inside a function cached with \`unstable_cache()\`. The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual Request, but caches must be able to be produced before a Request so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`
- )
+ throw createConnectionInUnstableCacheError(workStore.route)
case 'generate-static-params':
throw new Error(
`Route ${workStore.route} used \`connection()\` inside \`generateStaticParams\`. This is not supported because \`generateStaticParams\` runs at build time without an HTTP request. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context`
diff --git a/packages/next/src/server/request/cookies.ts b/packages/next/src/server/request/cookies.ts
index ace68cf773a8..08198d841e5e 100644
--- a/packages/next/src/server/request/cookies.ts
+++ b/packages/next/src/server/request/cookies.ts
@@ -31,6 +31,10 @@ import { isRequestAPICallableInsideAfter } from './utils'
import { applyOwnerStack } from '../dynamic-rendering-utils'
import { InvariantError } from '../../shared/lib/invariant-error'
import { RenderStage } from '../app-render/staged-rendering'
+import {
+ createCookiesInUseCacheError,
+ createCookiesInUnstableCacheError,
+} from '../use-cache/use-cache-messages'
export function cookies(): Promise {
const callingExpression = 'cookies'
@@ -65,17 +69,13 @@ export function cookies(): Promise {
if (workUnitStore) {
switch (workUnitStore.type) {
case 'cache':
- const error = new Error(
- `Route ${workStore.route} used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`
- )
+ const error = createCookiesInUseCacheError(workStore.route)
Error.captureStackTrace(error, cookies)
applyOwnerStack(error)
workStore.invalidDynamicUsageError ??= error
throw error
case 'unstable-cache':
- throw new Error(
- `Route ${workStore.route} used \`cookies()\` inside a function cached with \`unstable_cache()\`. Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`
- )
+ throw createCookiesInUnstableCacheError(workStore.route)
case 'generate-static-params':
throw new Error(
`Route ${workStore.route} used \`cookies()\` inside \`generateStaticParams\`. This is not supported because \`generateStaticParams\` runs at build time without an HTTP request. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context`
diff --git a/packages/next/src/server/request/draft-mode.ts b/packages/next/src/server/request/draft-mode.ts
index 29f504c800ab..bd84e57cf3a9 100644
--- a/packages/next/src/server/request/draft-mode.ts
+++ b/packages/next/src/server/request/draft-mode.ts
@@ -20,6 +20,10 @@ import { StaticGenBailoutError } from '../../client/components/static-generation
import { DynamicServerError } from '../../client/components/hooks-server-context'
import { InvariantError } from '../../shared/lib/invariant-error'
import { delayUntilRuntimeStage } from '../dynamic-rendering-utils'
+import {
+ createDraftModeMutationInUseCacheError,
+ createDraftModeMutationInUnstableCacheError,
+} from '../use-cache/use-cache-messages'
import { ReflectAdapter } from '../web/spec-extension/adapters/reflect'
import { applyOwnerStack } from '../dynamic-rendering-utils'
@@ -203,8 +207,9 @@ function trackDynamicDraftMode(expression: string, constructorOpt: Function) {
switch (workUnitStore.type) {
case 'cache':
case 'private-cache': {
- const error = new Error(
- `Route ${workStore.route} used "${expression}" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`
+ const error = createDraftModeMutationInUseCacheError(
+ workStore.route,
+ expression
)
Error.captureStackTrace(error, constructorOpt)
applyOwnerStack(error)
@@ -212,8 +217,9 @@ function trackDynamicDraftMode(expression: string, constructorOpt: Function) {
throw error
}
case 'unstable-cache':
- throw new Error(
- `Route ${workStore.route} used "${expression}" inside a function cached with \`unstable_cache()\`. The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`
+ throw createDraftModeMutationInUnstableCacheError(
+ workStore.route,
+ expression
)
case 'prerender':
diff --git a/packages/next/src/server/request/headers.ts b/packages/next/src/server/request/headers.ts
index f5244b31d94a..6006de0e7b15 100644
--- a/packages/next/src/server/request/headers.ts
+++ b/packages/next/src/server/request/headers.ts
@@ -29,6 +29,10 @@ import { isRequestAPICallableInsideAfter } from './utils'
import { applyOwnerStack } from '../dynamic-rendering-utils'
import { InvariantError } from '../../shared/lib/invariant-error'
import { RenderStage } from '../app-render/staged-rendering'
+import {
+ createHeadersInUseCacheError,
+ createHeadersInUnstableCacheError,
+} from '../use-cache/use-cache-messages'
/**
* This function allows you to read the HTTP incoming request headers in
@@ -65,18 +69,14 @@ export function headers(): Promise {
if (workUnitStore) {
switch (workUnitStore.type) {
case 'cache': {
- const error = new Error(
- `Route ${workStore.route} used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`
- )
+ const error = createHeadersInUseCacheError(workStore.route)
Error.captureStackTrace(error, headers)
applyOwnerStack(error)
workStore.invalidDynamicUsageError ??= error
throw error
}
case 'unstable-cache':
- throw new Error(
- `Route ${workStore.route} used \`headers()\` inside a function cached with \`unstable_cache()\`. Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`
- )
+ throw createHeadersInUnstableCacheError(workStore.route)
case 'generate-static-params':
throw new Error(
`Route ${workStore.route} used \`headers()\` inside \`generateStaticParams\`. This is not supported because \`generateStaticParams\` runs at build time without an HTTP request. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context`
diff --git a/packages/next/src/server/request/utils.ts b/packages/next/src/server/request/utils.ts
index 5053fb00452c..e3885d2baf02 100644
--- a/packages/next/src/server/request/utils.ts
+++ b/packages/next/src/server/request/utils.ts
@@ -1,6 +1,7 @@
import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'
import { afterTaskAsyncStorage } from '../app-render/after-task-async-storage.external'
import type { WorkStore } from '../app-render/work-async-storage.external'
+import { createSearchParamsInUseCacheError } from '../use-cache/use-cache-messages'
export function throwWithStaticGenerationBailoutErrorWithDynamicError(
route: string,
@@ -15,9 +16,7 @@ export function throwForSearchParamsAccessInUseCache(
workStore: WorkStore,
constructorOpt: Function
): never {
- const error = new Error(
- `Route ${workStore.route} used \`searchParams\` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await \`searchParams\` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`
- )
+ const error = createSearchParamsInUseCacheError(workStore.route)
Error.captureStackTrace(error, constructorOpt)
workStore.invalidDynamicUsageError ??= error
diff --git a/packages/next/src/server/route-modules/app-route/module.ts b/packages/next/src/server/route-modules/app-route/module.ts
index 6aee038f75bd..d75473b1c80c 100644
--- a/packages/next/src/server/route-modules/app-route/module.ts
+++ b/packages/next/src/server/route-modules/app-route/module.ts
@@ -88,6 +88,10 @@ import { executeRevalidates } from '../../revalidation-utils'
import { trackPendingModules } from '../../app-render/module-loading/track-module-loading.external'
import { InvariantError } from '../../../shared/lib/invariant-error'
import { createPrerenderResumeDataCache } from '../../resume-data-cache/resume-data-cache'
+import {
+ createRouteHandlerRequestInUseCacheError,
+ createRouteHandlerRequestInUnstableCacheError,
+} from '../../use-cache/use-cache-messages'
export class WrappedNextRouterError {
constructor(
@@ -1324,12 +1328,11 @@ function trackDynamic(
case 'private-cache':
// TODO: Should we allow reading cookies and search params from the
// request for private caches in route handlers?
- throw new Error(
- `Route ${store.route} used "${expression}" inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use "${expression}" outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`
- )
+ throw createRouteHandlerRequestInUseCacheError(store.route, expression)
case 'unstable-cache':
- throw new Error(
- `Route ${store.route} used "${expression}" inside a function cached with "unstable_cache(...)". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use "${expression}" outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/app/api-reference/functions/unstable_cache`
+ throw createRouteHandlerRequestInUnstableCacheError(
+ store.route,
+ expression
)
case 'prerender':
const error = new Error(
diff --git a/packages/next/src/server/use-cache/cache-life.ts b/packages/next/src/server/use-cache/cache-life.ts
index b4d83c193931..5fcd4eb6d5f6 100644
--- a/packages/next/src/server/use-cache/cache-life.ts
+++ b/packages/next/src/server/use-cache/cache-life.ts
@@ -1,6 +1,7 @@
import { InvariantError } from '../../shared/lib/invariant-error'
import { workAsyncStorage } from '../app-render/work-async-storage.external'
import { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external'
+import { createCacheLifeOutsideUseCacheError } from './use-cache-messages'
export type CacheLife = {
// How long the client can cache a value without checking with the server.
@@ -94,9 +95,7 @@ export function cacheLife(profile: CacheLifeProfiles | CacheLife): void {
case 'unstable-cache':
case 'generate-static-params':
case undefined:
- throw new Error(
- '`cacheLife()` can only be called inside a "use cache" function.'
- )
+ throw createCacheLifeOutsideUseCacheError()
case 'cache':
case 'private-cache':
break
diff --git a/packages/next/src/server/use-cache/cache-tag.ts b/packages/next/src/server/use-cache/cache-tag.ts
index 3cbdbf924534..2dacbce54ddb 100644
--- a/packages/next/src/server/use-cache/cache-tag.ts
+++ b/packages/next/src/server/use-cache/cache-tag.ts
@@ -1,5 +1,6 @@
import { workUnitAsyncStorage } from '../app-render/work-unit-async-storage.external'
import { validateTags } from '../lib/patch-fetch'
+import { createCacheTagOutsideUseCacheError } from './use-cache-messages'
export function cacheTag(...tags: string[]): void {
if (!process.env.__NEXT_USE_CACHE) {
@@ -21,9 +22,7 @@ export function cacheTag(...tags: string[]): void {
case 'unstable-cache':
case 'generate-static-params':
case undefined:
- throw new Error(
- '`cacheTag()` can only be called inside a "use cache" function.'
- )
+ throw createCacheTagOutsideUseCacheError()
case 'cache':
case 'private-cache':
break
diff --git a/packages/next/src/server/use-cache/use-cache-messages.ts b/packages/next/src/server/use-cache/use-cache-messages.ts
new file mode 100644
index 000000000000..a88d9602deb4
--- /dev/null
+++ b/packages/next/src/server/use-cache/use-cache-messages.ts
@@ -0,0 +1,195 @@
+/**
+ * Centralised error factories for `"use cache"` / `"use cache: private"`
+ * misuse. Wording goal: name the constraint and the fix in one sentence,
+ * then link to the docs page that explains why.
+ *
+ * Importers: `request/cookies.ts`, `request/headers.ts`,
+ * `request/connection.ts`, `request/draft-mode.ts`, `request/utils.ts`,
+ * `route-modules/app-route/module.ts`, `use-cache/cache-tag.ts`,
+ * `use-cache/cache-life.ts`, `use-cache/use-cache-wrapper.ts`,
+ * `web/spec-extension/revalidate.ts`.
+ */
+
+const NEXT_REQUEST_IN_USE_CACHE =
+ 'https://nextjs.org/docs/messages/next-request-in-use-cache'
+
+const UNSTABLE_CACHE_API_DOCS =
+ 'https://nextjs.org/docs/app/api-reference/functions/unstable_cache'
+
+const NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE =
+ 'https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife'
+
+const REVALIDATING_GUIDE_DOCS =
+ 'https://nextjs.org/docs/app/getting-started/revalidating'
+
+const CACHE_TAG_API_DOCS =
+ 'https://nextjs.org/docs/app/api-reference/functions/cacheTag'
+
+const CACHE_LIFE_API_DOCS =
+ 'https://nextjs.org/docs/app/api-reference/functions/cacheLife'
+
+const USE_CACHE_PRIVATE_DIRECTIVE_DOCS =
+ 'https://nextjs.org/docs/app/api-reference/directives/use-cache-private'
+
+// ── Request APIs inside `"use cache"` ─────────────────────────────
+
+export function createCookiesInUseCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.\nLearn more: ${NEXT_REQUEST_IN_USE_CACHE}`
+ )
+}
+
+export function createCookiesInUnstableCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`cookies()\` can't be read inside \`unstable_cache()\`. Read it outside the cached function and pass what you need as an argument.\nLearn more: ${UNSTABLE_CACHE_API_DOCS}`
+ )
+}
+
+export function createHeadersInUseCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.\nLearn more: ${NEXT_REQUEST_IN_USE_CACHE}`
+ )
+}
+
+export function createHeadersInUnstableCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`headers()\` can't be read inside \`unstable_cache()\`. Read it outside the cached function and pass what you need as an argument.\nLearn more: ${UNSTABLE_CACHE_API_DOCS}`
+ )
+}
+
+export function createSearchParamsInUseCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`searchParams\` can't be read inside \`"use cache"\`. Await it outside the cached function and pass what you need as an argument.\nLearn more: ${NEXT_REQUEST_IN_USE_CACHE}`
+ )
+}
+
+export function createConnectionInPublicUseCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.\nLearn more: ${NEXT_REQUEST_IN_USE_CACHE}`
+ )
+}
+
+export function createConnectionInPrivateUseCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`connection()\` can't be used inside \`"use cache: private"\`. A private cache entry can be built before a navigation request, so it can't depend on one.\nLearn more: ${NEXT_REQUEST_IN_USE_CACHE}`
+ )
+}
+
+export function createConnectionInUnstableCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`connection()\` can't be used inside \`unstable_cache()\`. A cache entry can be built before any request exists, so it can't depend on one.\nLearn more: ${UNSTABLE_CACHE_API_DOCS}`
+ )
+}
+
+/**
+ * Used when `draftMode().enable()` or `.disable()` is called inside
+ * `"use cache"` or `"use cache: private"`. Reading `draftMode()` is fine
+ * inside a cache — toggling it is not.
+ */
+export function createDraftModeMutationInUseCacheError(
+ route: string,
+ expression: string
+): Error {
+ return new Error(
+ `Route "${route}": \`${expression}\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.\nLearn more: ${NEXT_REQUEST_IN_USE_CACHE}`
+ )
+}
+
+export function createDraftModeMutationInUnstableCacheError(
+ route: string,
+ expression: string
+): Error {
+ return new Error(
+ `Route "${route}": \`${expression}\` can't be called inside \`unstable_cache()\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.\nLearn more: ${UNSTABLE_CACHE_API_DOCS}`
+ )
+}
+
+// ── App Route handler — request data inside `"use cache"` ─────────
+
+export function createRouteHandlerRequestInUseCacheError(
+ route: string,
+ expression: string
+): Error {
+ return new Error(
+ `Route "${route}": \`${expression}\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.\nLearn more: ${NEXT_REQUEST_IN_USE_CACHE}`
+ )
+}
+
+export function createRouteHandlerRequestInUnstableCacheError(
+ route: string,
+ expression: string
+): Error {
+ return new Error(
+ `Route "${route}": \`${expression}\` can't be read inside \`unstable_cache()\`. Read it outside the cached function and pass what you need as an argument.\nLearn more: ${UNSTABLE_CACHE_API_DOCS}`
+ )
+}
+
+// ── Revalidation inside `"use cache"` ─────────────────────────────
+
+/**
+ * Only reachable via Server Action → `"use cache"` → revalidate.
+ * Render-phase revalidate calls are caught earlier with a different message.
+ */
+export function createRevalidateInUseCacheError(
+ route: string,
+ expression: string
+): Error {
+ return new Error(
+ `Route "${route}": \`${expression}\` can't be called inside \`"use cache"\`. Revalidation must run outside renders and cached functions so caches stay consistent.\nLearn more: ${REVALIDATING_GUIDE_DOCS}`
+ )
+}
+
+export function createRevalidateInUnstableCacheError(
+ route: string,
+ expression: string
+): Error {
+ return new Error(
+ `Route "${route}": \`${expression}\` can't be called inside \`unstable_cache()\`. Revalidation must run outside renders and cached functions so caches stay consistent.\nLearn more: ${REVALIDATING_GUIDE_DOCS}`
+ )
+}
+
+// ── Cache helpers called outside `"use cache"` ────────────────────
+
+export function createCacheTagOutsideUseCacheError(): Error {
+ return new Error(
+ `\`cacheTag()\` can only be called inside a \`"use cache"\` function.\nLearn more: ${CACHE_TAG_API_DOCS}`
+ )
+}
+
+export function createCacheLifeOutsideUseCacheError(): Error {
+ return new Error(
+ `\`cacheLife()\` can only be called inside a \`"use cache"\` function.\nLearn more: ${CACHE_LIFE_API_DOCS}`
+ )
+}
+
+// ── Nested `"use cache"` without outer `cacheLife()` ──────────────
+
+export const nestedCacheZeroRevalidateErrorMessage =
+ `A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. ` +
+ `Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.\n` +
+ `Learn more: ${NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE}`
+
+export const nestedCacheShortExpireErrorMessage =
+ `A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. ` +
+ `Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.\n` +
+ `Learn more: ${NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE}`
+
+// ── `"use cache: private"` placement errors ───────────────────────
+
+export function createUseCachePrivateInsidePublicUseCacheError(): Error {
+ return new Error(
+ `\`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.\nLearn more: ${USE_CACHE_PRIVATE_DIRECTIVE_DOCS}`
+ )
+}
+
+export function createUseCachePrivateInsideUnstableCacheError(): Error {
+ return new Error(
+ `\`"use cache: private"\` can't be used inside \`unstable_cache()\`.\nLearn more: ${USE_CACHE_PRIVATE_DIRECTIVE_DOCS}`
+ )
+}
+
+export function createUseCachePrivateOutsideRequestContextError(): Error {
+ return new Error(
+ `\`"use cache: private"\` needs an active request. It can't be used during \`generateStaticParams\` or other build-time contexts.\nLearn more: ${USE_CACHE_PRIVATE_DIRECTIVE_DOCS}`
+ )
+}
diff --git a/packages/next/src/server/use-cache/use-cache-wrapper.ts b/packages/next/src/server/use-cache/use-cache-wrapper.ts
index 5a178bf993e4..339440980a34 100644
--- a/packages/next/src/server/use-cache/use-cache-wrapper.ts
+++ b/packages/next/src/server/use-cache/use-cache-wrapper.ts
@@ -63,6 +63,13 @@ import {
UseCacheDeadlockError,
UseCacheTimeoutError,
} from './use-cache-errors'
+import {
+ createUseCachePrivateInsidePublicUseCacheError,
+ createUseCachePrivateInsideUnstableCacheError,
+ createUseCachePrivateOutsideRequestContextError,
+ nestedCacheShortExpireErrorMessage,
+ nestedCacheZeroRevalidateErrorMessage,
+} from './use-cache-messages'
import {
createHangingInputAbortSignal,
postponeWithTracking,
@@ -278,22 +285,6 @@ const findSourceMapURL =
.findSourceMapURLDEV
: undefined
-const nestedCacheZeroRevalidateErrorMessage =
- `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`
-
-const nestedCacheShortExpireErrorMessage =
- `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`
-
// Tracks which root params each cache function has historically read. Used to
// compute the specific cache key upfront on subsequent invocations. In-memory
// only — after server restart, the coarse-key redirect entry in the cache
@@ -1557,18 +1548,12 @@ export async function cache(
)
case 'unstable-cache': {
throw wrapAsInvalidDynamicUsageError(
- new Error(
- // TODO: Add a link to an error documentation page when we have one.
- `${expression} must not be used within \`unstable_cache()\`.`
- )
+ createUseCachePrivateInsideUnstableCacheError()
)
}
case 'cache': {
throw wrapAsInvalidDynamicUsageError(
- new Error(
- // TODO: Add a link to an error documentation page when we have one.
- `${expression} must not be used within "use cache". It can only be nested inside of another ${expression}.`
- )
+ createUseCachePrivateInsidePublicUseCacheError()
)
}
case 'request':
@@ -1585,10 +1570,7 @@ export async function cache(
break
case 'generate-static-params':
throw wrapAsInvalidDynamicUsageError(
- new Error(
- // TODO: Add a link to an error documentation page when we have one.
- `${expression} cannot be used outside of a request context.`
- )
+ createUseCachePrivateOutsideRequestContextError()
)
default:
workUnitStore satisfies never
diff --git a/packages/next/src/server/web/spec-extension/revalidate.ts b/packages/next/src/server/web/spec-extension/revalidate.ts
index 0955c36fb146..822d182e0bb1 100644
--- a/packages/next/src/server/web/spec-extension/revalidate.ts
+++ b/packages/next/src/server/web/spec-extension/revalidate.ts
@@ -17,6 +17,10 @@ import {
} from '../../../shared/lib/action-revalidation-kind'
import { removeTrailingSlash } from '../../../shared/lib/router/utils/remove-trailing-slash'
import { encodeCacheTag } from '../../lib/encode-cache-tag'
+import {
+ createRevalidateInUseCacheError,
+ createRevalidateInUnstableCacheError,
+} from '../../use-cache/use-cache-messages'
type CacheLifeConfig = {
expire?: number
@@ -145,13 +149,9 @@ function revalidate(
switch (workUnitStore.type) {
case 'cache':
case 'private-cache':
- throw new Error(
- `Route ${store.route} used "${expression}" inside a "use cache" which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`
- )
+ throw createRevalidateInUseCacheError(store.route, expression)
case 'unstable-cache':
- throw new Error(
- `Route ${store.route} used "${expression}" inside a function cached with "unstable_cache(...)" which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`
- )
+ throw createRevalidateInUnstableCacheError(store.route, expression)
case 'generate-static-params':
throw new Error(
`Route ${store.route} used "${expression}" inside \`generateStaticParams\` which is unsupported. To ensure revalidation is performed consistently it must always happen outside of renders and cached functions. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`
From f550d18c718f8ff9cddf9532327e12cdc630e709 Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Mon, 1 Jun 2026 13:55:56 +0200
Subject: [PATCH 2/6] fix snapshots
---
.../cache-components-errors.test.ts | 96 ++++++++++++-------
1 file changed, 60 insertions(+), 36 deletions(-)
diff --git a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
index d53a40a96085..47fd74bd2a18 100644
--- a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
+++ b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
@@ -2609,8 +2609,9 @@ describe('Cache Components Errors', () => {
await expect(browser).toDisplayRedbox(`
{
- "code": "E831",
- "description": "Route /use-cache-cookies used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1298",
+ "description": "Route "/use-cache-cookies": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-cookies/page.tsx (22:18) @ CookiesReadingComponent
@@ -2639,7 +2640,8 @@ describe('Cache Components Errors', () => {
if (isTurbopack) {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-cookies used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-cookies": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at CookiesReadingComponent (app/use-cache-cookies/page.tsx:22:18)
at Page (app/use-cache-cookies/page.tsx:10:7)
20 | // in userland.
@@ -2718,8 +2720,9 @@ describe('Cache Components Errors', () => {
await expect(browser).toDisplayRedbox(`
{
- "code": "E829",
- "description": "Route /use-cache-draft-mode used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1302",
+ "description": "Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-draft-mode/page.tsx (20:26) @ DraftModeEnablingComponent
@@ -2748,7 +2751,8 @@ describe('Cache Components Errors', () => {
if (isDebugPrerender) {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-draft-mode used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at DraftModeEnablingComponent (app/use-cache-draft-mode/page.tsx:20:26)
at Page (app/use-cache-draft-mode/page.tsx:9:7)
18 | // here to ensure that this error is shown even when it's caught in userland.
@@ -2826,8 +2830,9 @@ describe('Cache Components Errors', () => {
await expect(browser).toDisplayRedbox(`
{
- "code": "E833",
- "description": "Route /use-cache-headers used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1292",
+ "description": "Route "/use-cache-headers": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-headers/page.tsx (21:18) @ HeadersReadingComponent
@@ -2856,7 +2861,8 @@ describe('Cache Components Errors', () => {
if (isTurbopack) {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-headers used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-headers": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at HeadersReadingComponent (app/use-cache-headers/page.tsx:21:18)
at Page (app/use-cache-headers/page.tsx:10:7)
19 | // to ensure that this error is shown even when it's caught in userland.
@@ -2933,8 +2939,9 @@ describe('Cache Components Errors', () => {
await expect(browser).toDisplayRedbox(`
{
- "code": "E841",
- "description": "Route /use-cache-connection used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1305",
+ "description": "Route "/use-cache-connection": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-connection/page.tsx (21:21) @ ConnectionCallingComponent
@@ -2963,7 +2970,8 @@ describe('Cache Components Errors', () => {
if (isTurbopack) {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-connection used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-connection": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at ConnectionCallingComponent (app/use-cache-connection/page.tsx:21:21)
at Page (app/use-cache-connection/page.tsx:10:7)
19 | // here to ensure that this error is shown even when it's caught in userland.
@@ -3299,8 +3307,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
],
},
],
- "code": "E1244",
- "description": "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",
+ "code": "E394",
+ "description": "A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/use-cache-low-expire/nested/page.tsx (20:14) @ Page
@@ -3328,7 +3337,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isTurbopack) {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: 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
+ "Error: A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife
at async Page (app/use-cache-low-expire/nested/page.tsx:20:14)
18 | let result: number | undefined
19 | try {
@@ -3704,8 +3714,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
],
},
],
- "code": "E1245",
- "description": "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",
+ "code": "E394",
+ "description": "A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/use-cache-revalidate-0/nested/page.tsx (20:14) @ Page
@@ -3733,7 +3744,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isTurbopack) {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: 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
+ "Error: A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife
at async Page (app/use-cache-revalidate-0/nested/page.tsx:20:14)
18 | let result: number | undefined
19 | try {
@@ -4090,8 +4102,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E831",
- "description": "Route /use-cache-cookies-third-party used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1298",
+ "description": "Route "/use-cache-cookies-third-party": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-cookies-third-party/page.tsx (10:7) @ Page
@@ -4119,7 +4132,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isTurbopack) {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-cookies-third-party used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-cookies-third-party": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at Page (app/use-cache-cookies-third-party/page.tsx:10:7)
8 | which triggers an error.
9 |
@@ -4189,8 +4203,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E829",
- "description": "Route /use-cache-draft-mode-third-party used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1302",
+ "description": "Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-draft-mode-third-party/page.tsx (10:7) @ Page
@@ -4218,7 +4233,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isDebugPrerender) {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-draft-mode-third-party used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at Page (app/use-cache-draft-mode-third-party/page.tsx:10:7)
8 | which triggers an error.
9 |
@@ -4287,8 +4303,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E833",
- "description": "Route /use-cache-headers-third-party used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1292",
+ "description": "Route "/use-cache-headers-third-party": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-headers-third-party/page.tsx (10:7) @ Page
@@ -4316,7 +4333,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isTurbopack) {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-headers-third-party used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-headers-third-party": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at Page (app/use-cache-headers-third-party/page.tsx:10:7)
8 | which triggers an error.
9 |
@@ -4386,8 +4404,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E841",
- "description": "Route /use-cache-connection-third-party used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1305",
+ "description": "Route "/use-cache-connection-third-party": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-connection-third-party/page.tsx (10:7) @ Page
@@ -4415,7 +4434,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isTurbopack) {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-connection-third-party used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-connection-third-party": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at Page (app/use-cache-connection-third-party/page.tsx:10:7)
8 | which triggers an error.
9 |
@@ -4489,8 +4509,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isTurbopack) {
await expect(browser).toDisplayRedbox(`
{
- "code": "E1016",
- "description": ""use cache: private" must not be used within \`unstable_cache()\`.",
+ "code": "E1295",
+ "description": "\`"use cache: private"\` can't be used inside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
"environmentLabel": "Server",
"label": "Runtime Error",
"source": "app/use-cache-private-in-unstable-cache/page.tsx (21:38) @
@@ -4536,7 +4557,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isDebugPrerender) {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within \`unstable_cache()\`.
+ "Error: \`"use cache: private"\` can't be used inside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at (app/use-cache-private-in-unstable-cache/page.tsx:21:38)
at async ComponentWithCachedData (app/use-cache-private-in-unstable-cache/page.tsx:16:16)
19 | }
@@ -4617,8 +4639,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E1001",
- "description": ""use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".",
+ "code": "E1293",
+ "description": "\`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
"environmentLabel": "Prerender",
"label": "Runtime Error",
"source": "app/use-cache-private-in-use-cache/page.tsx (15:1) @ Private
@@ -4647,7 +4670,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isDebugPrerender) {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
+ "Error: \`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at Private (app/use-cache-private-in-use-cache/page.tsx:15:1)
13 | }
14 |
From e577eb67d2e9ad056c499fac220de436a3217c29 Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Mon, 1 Jun 2026 13:56:56 +0200
Subject: [PATCH 3/6] update snapshots
---
.../cache-components-errors.test.ts | 39 ++++++++++++-------
1 file changed, 26 insertions(+), 13 deletions(-)
diff --git a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
index 47fd74bd2a18..6499c9a223da 100644
--- a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
+++ b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
@@ -2659,7 +2659,8 @@ describe('Cache Components Errors', () => {
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-cookies used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-cookies": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a (app/use-cache-cookies/page.tsx:22:11)
20 | // in userland.
21 | try {
@@ -2790,7 +2791,8 @@ describe('Cache Components Errors', () => {
} else {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-draft-mode used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a (app/use-cache-draft-mode/page.tsx:20:26)
18 | // here to ensure that this error is shown even when it's caught in userland.
19 | try {
@@ -2880,7 +2882,8 @@ describe('Cache Components Errors', () => {
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-headers used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-headers": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a (app/use-cache-headers/page.tsx:21:11)
19 | // to ensure that this error is shown even when it's caught in userland.
20 | try {
@@ -2989,7 +2992,8 @@ describe('Cache Components Errors', () => {
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-connection used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-connection": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a (app/use-cache-connection/page.tsx:21:11)
19 | // here to ensure that this error is shown even when it's caught in userland.
20 | try {
@@ -3367,7 +3371,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: 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
+ "Error: A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife
at async k (app/use-cache-low-expire/nested/page.tsx:20:14)
18 | let result: number | undefined
19 | try {
@@ -3774,7 +3779,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: 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
+ "Error: A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife
at async k (app/use-cache-revalidate-0/nested/page.tsx:20:14)
18 | let result: number | undefined
19 | try {
@@ -4150,7 +4156,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-cookies-third-party used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-cookies-third-party": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at ignore-listed frames
To get a more detailed stack trace and pinpoint the issue, try one of the following:
- Start the app in development mode by running \`next dev\`, then open "/use-cache-cookies-third-party" in your browser to investigate the error.
@@ -4270,7 +4277,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-draft-mode-third-party used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at ignore-listed frames
To get a more detailed stack trace and pinpoint the issue, try one of the following:
- Start the app in development mode by running \`next dev\`, then open "/use-cache-draft-mode-third-party" in your browser to investigate the error.
@@ -4351,7 +4359,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-headers-third-party used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-headers-third-party": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at ignore-listed frames
To get a more detailed stack trace and pinpoint the issue, try one of the following:
- Start the app in development mode by running \`next dev\`, then open "/use-cache-headers-third-party" in your browser to investigate the error.
@@ -4452,7 +4461,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-connection-third-party used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-connection-third-party": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at ignore-listed frames
To get a more detailed stack trace and pinpoint the issue, try one of the following:
- Start the app in development mode by running \`next dev\`, then open "/use-cache-connection-third-party" in your browser to investigate the error.
@@ -4596,7 +4606,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within \`unstable_cache()\`.
+ "Error: \`"use cache: private"\` can't be used inside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at (app/use-cache-private-in-unstable-cache/page.tsx:21:38)
at async g (app/use-cache-private-in-unstable-cache/page.tsx:16:16)
19 | }
@@ -4710,7 +4721,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "⨯ Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
+ "⨯ Error: \`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at (app/use-cache-private-in-use-cache/page.tsx:15:1)
at a ()
13 | }
@@ -4722,7 +4734,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
18 | return Private
{
digest: ''
}
- Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
+ Error: \`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at (app/use-cache-private-in-use-cache/page.tsx:15:1)
at b ()
13 | }
From a988d6f95bac82849eaadadaa958ce28b08a55b8 Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Mon, 1 Jun 2026 14:18:15 +0200
Subject: [PATCH 4/6] factories for nested-cache messages so error-code tool
can match
---
packages/next/errors.json | 4 ++-
.../server/use-cache/use-cache-messages.ts | 33 ++++++++++++-------
.../src/server/use-cache/use-cache-wrapper.ts | 28 ++++++++--------
.../cache-components-errors.test.ts | 4 +--
4 files changed, 41 insertions(+), 28 deletions(-)
diff --git a/packages/next/errors.json b/packages/next/errors.json
index d008b7c059d7..a0551347db11 100644
--- a/packages/next/errors.json
+++ b/packages/next/errors.json
@@ -1304,5 +1304,7 @@
"1303": "Route \"%s\": \\`headers()\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
"1304": "Route \"%s\": \\`connection()\\` can't be used inside \\`\"use cache: private\"\\`. A private cache entry can be built before a navigation request, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"1305": "Route \"%s\": \\`connection()\\` can't be used inside \\`\"use cache\"\\`. A cache entry can be built before any request exists, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
- "1306": "This \"use cache\" has a dynamic cache life that was propagated to its parent.\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife"
+ "1306": "This \"use cache\" has a dynamic cache life that was propagated to its parent.\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
+ "1307": "A nested \\`\"use cache\"\\` with a short \\`expire\\` (under 5 minutes) is inside an outer \\`\"use cache\"\\` that has no \\`cacheLife()\\`. Add \\`cacheLife()\\` to the outer one to choose: a longer \\`expire\\` to prerender it, or a short \\`expire\\` to keep it dynamic.\\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
+ "1308": "A nested \\`\"use cache\"\\` with \\`revalidate: 0\\` is inside an outer \\`\"use cache\"\\` that has no \\`cacheLife()\\`. Add \\`cacheLife()\\` to the outer one to choose: a non-zero \\`revalidate\\` to prerender it, or \\`revalidate: 0\\` to keep it dynamic.\\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife"
}
diff --git a/packages/next/src/server/use-cache/use-cache-messages.ts b/packages/next/src/server/use-cache/use-cache-messages.ts
index a88d9602deb4..b167ec3393c5 100644
--- a/packages/next/src/server/use-cache/use-cache-messages.ts
+++ b/packages/next/src/server/use-cache/use-cache-messages.ts
@@ -16,9 +16,6 @@ const NEXT_REQUEST_IN_USE_CACHE =
const UNSTABLE_CACHE_API_DOCS =
'https://nextjs.org/docs/app/api-reference/functions/unstable_cache'
-const NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE =
- 'https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife'
-
const REVALIDATING_GUIDE_DOCS =
'https://nextjs.org/docs/app/getting-started/revalidating'
@@ -164,15 +161,29 @@ export function createCacheLifeOutsideUseCacheError(): Error {
// ── Nested `"use cache"` without outer `cacheLife()` ──────────────
-export const nestedCacheZeroRevalidateErrorMessage =
- `A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. ` +
- `Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.\n` +
- `Learn more: ${NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE}`
+/**
+ * Factories (not exported strings) so the error-code tool can statically
+ * match the message at the `new Error("…")` call site and keep the stable
+ * E1244 / E1245 entries in `errors.json`. The chained `NestedDynamicUseCacheError`
+ * captured at the inner `"use cache"` is passed as `cause`.
+ */
+export function createNestedCacheZeroRevalidateError(
+ cause: Error | undefined
+): Error {
+ return new Error(
+ `A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife`,
+ { cause }
+ )
+}
-export const nestedCacheShortExpireErrorMessage =
- `A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. ` +
- `Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.\n` +
- `Learn more: ${NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE}`
+export function createNestedCacheShortExpireError(
+ cause: Error | undefined
+): Error {
+ return new Error(
+ `A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife`,
+ { cause }
+ )
+}
// ── `"use cache: private"` placement errors ───────────────────────
diff --git a/packages/next/src/server/use-cache/use-cache-wrapper.ts b/packages/next/src/server/use-cache/use-cache-wrapper.ts
index 339440980a34..45e795bc2373 100644
--- a/packages/next/src/server/use-cache/use-cache-wrapper.ts
+++ b/packages/next/src/server/use-cache/use-cache-wrapper.ts
@@ -64,11 +64,11 @@ import {
UseCacheTimeoutError,
} from './use-cache-errors'
import {
+ createNestedCacheShortExpireError,
+ createNestedCacheZeroRevalidateError,
createUseCachePrivateInsidePublicUseCacheError,
createUseCachePrivateInsideUnstableCacheError,
createUseCachePrivateOutsideRequestContextError,
- nestedCacheShortExpireErrorMessage,
- nestedCacheZeroRevalidateErrorMessage,
} from './use-cache-messages'
import {
createHangingInputAbortSignal,
@@ -2037,9 +2037,9 @@ export async function cache(
if (rdcResult.entry.revalidate === 0) {
if (rdcResult.hasExplicitRevalidate === false) {
throw wrapAsInvalidDynamicUsageError(
- new Error(nestedCacheZeroRevalidateErrorMessage, {
- cause: rdcResult.dynamicNestedCacheError,
- })
+ createNestedCacheZeroRevalidateError(
+ rdcResult.dynamicNestedCacheError
+ )
)
}
debug?.(
@@ -2050,9 +2050,9 @@ export async function cache(
} else {
if (rdcResult.hasExplicitExpire === false) {
throw wrapAsInvalidDynamicUsageError(
- new Error(nestedCacheShortExpireErrorMessage, {
- cause: rdcResult.dynamicNestedCacheError,
- })
+ createNestedCacheShortExpireError(
+ rdcResult.dynamicNestedCacheError
+ )
)
}
debug?.(
@@ -2089,9 +2089,9 @@ export async function cache(
rdcResult.hasExplicitRevalidate === false
) {
throw wrapAsInvalidDynamicUsageError(
- new Error(nestedCacheZeroRevalidateErrorMessage, {
- cause: rdcResult.dynamicNestedCacheError,
- })
+ createNestedCacheZeroRevalidateError(
+ rdcResult.dynamicNestedCacheError
+ )
)
}
if (
@@ -2099,9 +2099,9 @@ export async function cache(
rdcResult.hasExplicitExpire === false
) {
throw wrapAsInvalidDynamicUsageError(
- new Error(nestedCacheShortExpireErrorMessage, {
- cause: rdcResult.dynamicNestedCacheError,
- })
+ createNestedCacheShortExpireError(
+ rdcResult.dynamicNestedCacheError
+ )
)
}
// We delay the cache here so that it doesn't resolve in the static task --
diff --git a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
index 6499c9a223da..4bd6cfc4b312 100644
--- a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
+++ b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
@@ -3311,7 +3311,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
],
},
],
- "code": "E394",
+ "code": "E1307",
"description": "A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.
Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
"environmentLabel": "Server",
@@ -3719,7 +3719,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
],
},
],
- "code": "E394",
+ "code": "E1308",
"description": "A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.
Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
"environmentLabel": "Server",
From 1206872cb7922ac86d4c6e697585e8e351a24a07 Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Mon, 1 Jun 2026 14:34:18 +0200
Subject: [PATCH 5/6] regenerate errors.json from canary baseline
---
packages/next/errors.json | 43 +++++++++----------
.../cache-components-errors.test.ts | 24 +++++------
2 files changed, 33 insertions(+), 34 deletions(-)
diff --git a/packages/next/errors.json b/packages/next/errors.json
index a0551347db11..878357d2335e 100644
--- a/packages/next/errors.json
+++ b/packages/next/errors.json
@@ -1285,26 +1285,25 @@
"1284": "Cache Components error recovery expected an original prerender store",
"1285": "Cache Components error recovery expected an original resume data cache",
"1286": "Route \"%s\": Could not validate that a segment in your UI has instant navigation.",
- "1287": "\\`cacheLife()\\` can only be called inside a \\`\"use cache\"\\` function.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/cacheLife",
- "1288": "\\`\"use cache: private\"\\` needs an active request. It can't be used during \\`generateStaticParams\\` or other build-time contexts.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
- "1289": "Route \"%s\": \\`searchParams\\` can't be read inside \\`\"use cache\"\\`. Await it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
- "1290": "Route \"%s\": \\`cookies()\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
- "1291": "\\`cacheTag()\\` can only be called inside a \\`\"use cache\"\\` function.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/cacheTag",
- "1292": "Route \"%s\": \\`headers()\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
- "1293": "\\`\"use cache: private\"\\` can't be nested inside \\`\"use cache\"\\`. It can only be nested inside another \\`\"use cache: private\"\\`.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
- "1294": "Route \"%s\": \\`%s\\` can't be called inside \\`\"use cache\"\\`. Revalidation must run outside renders and cached functions so caches stay consistent.\\nLearn more: https://nextjs.org/docs/app/getting-started/revalidating",
- "1295": "\\`\"use cache: private\"\\` can't be used inside \\`unstable_cache()\\`.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
- "1296": "Route \"%s\": \\`%s\\` can't be called inside \\`unstable_cache()\\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
- "1297": "Route \"%s\": \\`%s\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
- "1298": "Route \"%s\": \\`cookies()\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
- "1299": "Route \"%s\": \\`%s\\` can't be called inside \\`unstable_cache()\\`. Revalidation must run outside renders and cached functions so caches stay consistent.\\nLearn more: https://nextjs.org/docs/app/getting-started/revalidating",
- "1300": "Route \"%s\": \\`connection()\\` can't be used inside \\`unstable_cache()\\`. A cache entry can be built before any request exists, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
- "1301": "Route \"%s\": \\`%s\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
- "1302": "Route \"%s\": \\`%s\\` can't be called inside \\`\"use cache\"\\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
- "1303": "Route \"%s\": \\`headers()\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
- "1304": "Route \"%s\": \\`connection()\\` can't be used inside \\`\"use cache: private\"\\`. A private cache entry can be built before a navigation request, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
- "1305": "Route \"%s\": \\`connection()\\` can't be used inside \\`\"use cache\"\\`. A cache entry can be built before any request exists, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
- "1306": "This \"use cache\" has a dynamic cache life that was propagated to its parent.\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
- "1307": "A nested \\`\"use cache\"\\` with a short \\`expire\\` (under 5 minutes) is inside an outer \\`\"use cache\"\\` that has no \\`cacheLife()\\`. Add \\`cacheLife()\\` to the outer one to choose: a longer \\`expire\\` to prerender it, or a short \\`expire\\` to keep it dynamic.\\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
- "1308": "A nested \\`\"use cache\"\\` with \\`revalidate: 0\\` is inside an outer \\`\"use cache\"\\` that has no \\`cacheLife()\\`. Add \\`cacheLife()\\` to the outer one to choose: a non-zero \\`revalidate\\` to prerender it, or \\`revalidate: 0\\` to keep it dynamic.\\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife"
+ "1287": "A nested \\`\"use cache\"\\` with a short \\`expire\\` (under 5 minutes) is inside an outer \\`\"use cache\"\\` that has no \\`cacheLife()\\`. Add \\`cacheLife()\\` to the outer one to choose: a longer \\`expire\\` to prerender it, or a short \\`expire\\` to keep it dynamic.\\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
+ "1288": "\\`cacheLife()\\` can only be called inside a \\`\"use cache\"\\` function.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/cacheLife",
+ "1289": "\\`\"use cache: private\"\\` needs an active request. It can't be used during \\`generateStaticParams\\` or other build-time contexts.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
+ "1290": "Route \"%s\": \\`searchParams\\` can't be read inside \\`\"use cache\"\\`. Await it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1291": "Route \"%s\": \\`cookies()\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1292": "\\`cacheTag()\\` can only be called inside a \\`\"use cache\"\\` function.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/cacheTag",
+ "1293": "Route \"%s\": \\`headers()\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1294": "\\`\"use cache: private\"\\` can't be nested inside \\`\"use cache\"\\`. It can only be nested inside another \\`\"use cache: private\"\\`.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
+ "1295": "Route \"%s\": \\`%s\\` can't be called inside \\`\"use cache\"\\`. Revalidation must run outside renders and cached functions so caches stay consistent.\\nLearn more: https://nextjs.org/docs/app/getting-started/revalidating",
+ "1296": "\\`\"use cache: private\"\\` can't be used inside \\`unstable_cache()\\`.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
+ "1297": "Route \"%s\": \\`%s\\` can't be called inside \\`unstable_cache()\\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1298": "Route \"%s\": \\`%s\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1299": "Route \"%s\": \\`cookies()\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1300": "Route \"%s\": \\`%s\\` can't be called inside \\`unstable_cache()\\`. Revalidation must run outside renders and cached functions so caches stay consistent.\\nLearn more: https://nextjs.org/docs/app/getting-started/revalidating",
+ "1301": "Route \"%s\": \\`connection()\\` can't be used inside \\`unstable_cache()\\`. A cache entry can be built before any request exists, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1302": "Route \"%s\": \\`%s\\` can't be read inside \\`\"use cache\"\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1303": "A nested \\`\"use cache\"\\` with \\`revalidate: 0\\` is inside an outer \\`\"use cache\"\\` that has no \\`cacheLife()\\`. Add \\`cacheLife()\\` to the outer one to choose: a non-zero \\`revalidate\\` to prerender it, or \\`revalidate: 0\\` to keep it dynamic.\\nLearn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
+ "1304": "Route \"%s\": \\`%s\\` can't be called inside \\`\"use cache\"\\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1305": "Route \"%s\": \\`headers()\\` can't be read inside \\`unstable_cache()\\`. Read it outside the cached function and pass what you need as an argument.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
+ "1306": "Route \"%s\": \\`connection()\\` can't be used inside \\`\"use cache: private\"\\`. A private cache entry can be built before a navigation request, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "1307": "Route \"%s\": \\`connection()\\` can't be used inside \\`\"use cache\"\\`. A cache entry can be built before any request exists, so it can't depend on one.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache"
}
diff --git a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
index 4bd6cfc4b312..b4db6087f596 100644
--- a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
+++ b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
@@ -2609,7 +2609,7 @@ describe('Cache Components Errors', () => {
await expect(browser).toDisplayRedbox(`
{
- "code": "E1298",
+ "code": "E1299",
"description": "Route "/use-cache-cookies": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
@@ -2721,7 +2721,7 @@ describe('Cache Components Errors', () => {
await expect(browser).toDisplayRedbox(`
{
- "code": "E1302",
+ "code": "E1304",
"description": "Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
@@ -2832,7 +2832,7 @@ describe('Cache Components Errors', () => {
await expect(browser).toDisplayRedbox(`
{
- "code": "E1292",
+ "code": "E1293",
"description": "Route "/use-cache-headers": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
@@ -2942,7 +2942,7 @@ describe('Cache Components Errors', () => {
await expect(browser).toDisplayRedbox(`
{
- "code": "E1305",
+ "code": "E1307",
"description": "Route "/use-cache-connection": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
@@ -3311,7 +3311,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
],
},
],
- "code": "E1307",
+ "code": "E1287",
"description": "A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.
Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
"environmentLabel": "Server",
@@ -3719,7 +3719,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
],
},
],
- "code": "E1308",
+ "code": "E1303",
"description": "A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.
Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife",
"environmentLabel": "Server",
@@ -4108,7 +4108,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E1298",
+ "code": "E1299",
"description": "Route "/use-cache-cookies-third-party": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
@@ -4210,7 +4210,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E1302",
+ "code": "E1304",
"description": "Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
@@ -4311,7 +4311,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E1292",
+ "code": "E1293",
"description": "Route "/use-cache-headers-third-party": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
@@ -4413,7 +4413,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E1305",
+ "code": "E1307",
"description": "Route "/use-cache-connection-third-party": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Prerender",
@@ -4519,7 +4519,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
if (isTurbopack) {
await expect(browser).toDisplayRedbox(`
{
- "code": "E1295",
+ "code": "E1296",
"description": "\`"use cache: private"\` can't be used inside \`unstable_cache()\`.
Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
"environmentLabel": "Server",
@@ -4650,7 +4650,7 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
await expect(browser).toDisplayRedbox(`
{
- "code": "E1293",
+ "code": "E1294",
"description": "\`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.
Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
"environmentLabel": "Prerender",
From cc598e5fbd7f3d20e92c7fccf9fcf41e4e7bf596 Mon Sep 17 00:00:00 2001
From: Aurora Scharff
Date: Mon, 1 Jun 2026 15:10:13 +0200
Subject: [PATCH 6/6] update remaining e2e tests for new use cache wording
---
.../cache-components-errors.test.ts | 80 ++++++++++++-------
.../app-dir/dynamic-data/dynamic-data.test.ts | 6 +-
.../use-cache-search-params.test.ts | 27 ++++---
test/e2e/app-dir/use-cache/use-cache.test.ts | 2 +-
4 files changed, 73 insertions(+), 42 deletions(-)
diff --git a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
index b4db6087f596..1d8dbc959706 100644
--- a/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
+++ b/test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts
@@ -2679,7 +2679,8 @@ describe('Cache Components Errors', () => {
} else {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-cookies used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-cookies": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at CookiesReadingComponent (webpack:///app/use-cache-cookies/page.tsx:22:18)
at Page (webpack:///app/use-cache-cookies/page.tsx:10:7)
20 | // in userland.
@@ -2697,7 +2698,8 @@ describe('Cache Components Errors', () => {
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-cookies used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-cookies": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a ()
at b ()
To get a more detailed stack trace and pinpoint the issue, try one of the following:
@@ -2771,7 +2773,8 @@ describe('Cache Components Errors', () => {
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-draft-mode used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at DraftModeEnablingComponent (webpack:///app/use-cache-draft-mode/page.tsx:20:26)
at Page (webpack:///app/use-cache-draft-mode/page.tsx:9:7)
18 | // here to ensure that this error is shown even when it's caught in userland.
@@ -2809,7 +2812,8 @@ describe('Cache Components Errors', () => {
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-draft-mode used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a ()
To get a more detailed stack trace and pinpoint the issue, try one of the following:
- Start the app in development mode by running \`next dev\`, then open "/use-cache-draft-mode" in your browser to investigate the error.
@@ -2902,7 +2906,8 @@ describe('Cache Components Errors', () => {
} else {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-headers used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-headers": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at HeadersReadingComponent (webpack:///app/use-cache-headers/page.tsx:21:18)
at Page (webpack:///app/use-cache-headers/page.tsx:10:7)
19 | // to ensure that this error is shown even when it's caught in userland.
@@ -2920,7 +2925,8 @@ describe('Cache Components Errors', () => {
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-headers used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-headers": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a ()
at b ()
To get a more detailed stack trace and pinpoint the issue, try one of the following:
@@ -3012,7 +3018,8 @@ describe('Cache Components Errors', () => {
} else {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-connection used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-connection": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at ConnectionCallingComponent (webpack:///app/use-cache-connection/page.tsx:21:21)
at Page (webpack:///app/use-cache-connection/page.tsx:10:7)
19 | // here to ensure that this error is shown even when it's caught in userland.
@@ -3030,7 +3037,8 @@ describe('Cache Components Errors', () => {
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-connection used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-connection": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a ()
at b ()
To get a more detailed stack trace and pinpoint the issue, try one of the following:
@@ -3402,7 +3410,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: 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
+ "Error: A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife
at async Page (webpack:///app/use-cache-low-expire/nested/page.tsx:20:14)
18 | let result: number | undefined
19 | try {
@@ -3431,7 +3440,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: 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
+ "Error: A nested \`"use cache"\` with a short \`expire\` (under 5 minutes) is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a longer \`expire\` to prerender it, or a short \`expire\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife
at a () {
[cause]: Nested dynamic "use cache": This "use cache" has a dynamic cache life that was propagated to its parent.
at b ()
@@ -3810,7 +3820,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: 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
+ "Error: A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife
at async Page (webpack:///app/use-cache-revalidate-0/nested/page.tsx:20:14)
18 | let result: number | undefined
19 | try {
@@ -3839,7 +3850,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: 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
+ "Error: A nested \`"use cache"\` with \`revalidate: 0\` is inside an outer \`"use cache"\` that has no \`cacheLife()\`. Add \`cacheLife()\` to the outer one to choose: a non-zero \`revalidate\` to prerender it, or \`revalidate: 0\` to keep it dynamic.
+ Learn more: https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife
at a () {
[cause]: Nested dynamic "use cache": This "use cache" has a dynamic cache life that was propagated to its parent.
at b ()
@@ -4169,7 +4181,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-cookies-third-party used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-cookies-third-party": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at Page (webpack:///app/use-cache-cookies-third-party/page.tsx:10:7)
8 | which triggers an error.
9 |
@@ -4186,7 +4199,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-cookies-third-party used \`cookies()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`cookies()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-cookies-third-party": \`cookies()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a ()
at b ()
To get a more detailed stack trace and pinpoint the issue, try one of the following:
@@ -4258,7 +4272,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-draft-mode-third-party used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at Page (webpack:///app/use-cache-draft-mode-third-party/page.tsx:10:7)
8 | which triggers an error.
9 |
@@ -4288,7 +4303,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-draft-mode-third-party used "draftMode().enable()" inside "use cache". The enabled status of \`draftMode()\` can be read in caches but you must not enable or disable \`draftMode()\` inside a cache. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read from a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a ()
To get a more detailed stack trace and pinpoint the issue, try one of the following:
- Start the app in development mode by running \`next dev\`, then open "/use-cache-draft-mode-third-party" in your browser to investigate the error.
@@ -4372,7 +4388,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-headers-third-party used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-headers-third-party": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at Page (webpack:///app/use-cache-headers-third-party/page.tsx:10:7)
8 | which triggers an error.
9 |
@@ -4389,7 +4406,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-headers-third-party used \`headers()\` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use \`headers()\` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-headers-third-party": \`headers()\` can't be read inside \`"use cache"\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a ()
at b ()
To get a more detailed stack trace and pinpoint the issue, try one of the following:
@@ -4474,7 +4492,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
if (isDebugPrerender) {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-connection-third-party used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-connection-third-party": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at Page (webpack:///app/use-cache-connection-third-party/page.tsx:10:7)
8 | which triggers an error.
9 |
@@ -4491,7 +4510,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: Route /use-cache-connection-third-party used \`connection()\` inside "use cache". The \`connection()\` function is used to indicate the subsequent code must only run when there is an actual request, but caches must be able to be produced before a request, so this function is not allowed in this scope. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache
+ "Error: Route "/use-cache-connection-third-party": \`connection()\` can't be used inside \`"use cache"\`. A cache entry can be built before any request exists, so it can't depend on one.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache
at a ()
at b ()
To get a more detailed stack trace and pinpoint the issue, try one of the following:
@@ -4536,8 +4556,9 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
} else {
await expect(browser).toDisplayRedbox(`
{
- "code": "E1016",
- "description": ""use cache: private" must not be used within \`unstable_cache()\`.",
+ "code": "E1296",
+ "description": "\`"use cache: private"\` can't be used inside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
"environmentLabel": "Server",
"label": "Runtime Error",
"source": "app/use-cache-private-in-unstable-cache/page.tsx (21:38) @ eval
@@ -4586,7 +4607,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within \`unstable_cache()\`.
+ "Error: \`"use cache: private"\` can't be used inside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at (webpack:///app/use-cache-private-in-unstable-cache/page.tsx:21:38)
at async ComponentWithCachedData (webpack:///app/use-cache-private-in-unstable-cache/page.tsx:16:16)
19 | }
@@ -4625,7 +4647,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within \`unstable_cache()\`.
+ "Error: \`"use cache: private"\` can't be used inside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at a ()
at b ()
at c ()
@@ -4701,7 +4724,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
+ "Error: \`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at Private (webpack:///app/use-cache-private-in-use-cache/page.tsx:15:1)
13 | }
14 |
@@ -4755,12 +4779,14 @@ Learn more: https://nextjs.org/docs/messages/blocking-route`
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "⨯ Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
+ "⨯ Error: \`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at a ()
at b () {
digest: ''
}
- Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
+ Error: \`"use cache: private"\` can't be nested inside \`"use cache"\`. It can only be nested inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private
at c ()
at d () {
digest: ''
diff --git a/test/e2e/app-dir/dynamic-data/dynamic-data.test.ts b/test/e2e/app-dir/dynamic-data/dynamic-data.test.ts
index 80697c1e2a97..ccbc7e4b9f56 100644
--- a/test/e2e/app-dir/dynamic-data/dynamic-data.test.ts
+++ b/test/e2e/app-dir/dynamic-data/dynamic-data.test.ts
@@ -378,13 +378,13 @@ describe('dynamic-data inside cache scope', () => {
// We expect this to fail
}
expect(next.cliOutput).toMatch(
- 'Error: Route /cookies used `cookies()` inside a function cached with `unstable_cache()`.'
+ 'Error: Route "/cookies": `cookies()` can\'t be read inside `unstable_cache()`. Read it outside the cached function and pass what you need as an argument.'
)
expect(next.cliOutput).toMatch(
- 'Error: Route /connection used `connection()` inside a function cached with `unstable_cache()`.'
+ 'Error: Route "/connection": `connection()` can\'t be used inside `unstable_cache()`. A cache entry can be built before any request exists, so it can\'t depend on one.'
)
expect(next.cliOutput).toMatch(
- 'Error: Route /headers used `headers()` inside a function cached with `unstable_cache()`.'
+ 'Error: Route "/headers": `headers()` can\'t be read inside `unstable_cache()`. Read it outside the cached function and pass what you need as an argument.'
)
})
}
diff --git a/test/e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts b/test/e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts
index b601d4dc7561..78fda9b800d7 100644
--- a/test/e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts
+++ b/test/e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts
@@ -3,7 +3,7 @@ import { assertNoConsoleErrors, waitForNoRedbox } from 'next-test-utils'
import stripAnsi from 'strip-ansi'
const getExpectedErrorMessage = (route: string) =>
- `Route ${route} used \`searchParams\` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await \`searchParams\` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache`
+ `Route "${route}": \`searchParams\` can't be read inside \`"use cache"\`. Await it outside the cached function and pass what you need as an argument.\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache`
const isCacheComponentsEnabled = process.env.__NEXT_CACHE_COMPONENTS === 'true'
@@ -48,8 +48,9 @@ describe('use-cache-search-params', () => {
} else {
await expect(browser).toDisplayRedbox(`
{
- "code": "E842",
- "description": "Route /search-params-used used \`searchParams\` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await \`searchParams\` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1290",
+ "description": "Route "/search-params-used": \`searchParams\` can't be read inside \`"use cache"\`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Cache",
"label": "Runtime Error",
"source": "app/search-params-used/page.tsx (8:17) @ Page
@@ -96,8 +97,9 @@ describe('use-cache-search-params', () => {
} else {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "code": "E842",
- "description": "Route /search-params-caught used \`searchParams\` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await \`searchParams\` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1290",
+ "description": "Route "/search-params-caught": \`searchParams\` can't be read inside \`"use cache"\`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/search-params-caught/page.tsx (11:5) @ Page
@@ -142,8 +144,9 @@ describe('use-cache-search-params', () => {
} else {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "code": "E842",
- "description": "Route /search-params-caught used \`searchParams\` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await \`searchParams\` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1290",
+ "description": "Route "/search-params-caught": \`searchParams\` can't be read inside \`"use cache"\`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/search-params-caught/page.tsx (11:5) @ Page
@@ -198,8 +201,9 @@ describe('use-cache-search-params', () => {
} else {
await expect(browser).toDisplayRedbox(`
{
- "code": "E842",
- "description": "Route /search-params-used-generate-metadata used \`searchParams\` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await \`searchParams\` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1290",
+ "description": "Route "/search-params-used-generate-metadata": \`searchParams\` can't be read inside \`"use cache"\`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Cache",
"label": "Runtime Error",
"source": "app/search-params-used-generate-metadata/page.tsx (9:17) @ generateMetadata
@@ -236,8 +240,9 @@ describe('use-cache-search-params', () => {
} else {
await expect(browser).toDisplayRedbox(`
{
- "code": "E842",
- "description": "Route /search-params-used-generate-viewport used \`searchParams\` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await \`searchParams\` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "code": "E1290",
+ "description": "Route "/search-params-used-generate-viewport": \`searchParams\` can't be read inside \`"use cache"\`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Cache",
"label": "Runtime Error",
"source": "app/search-params-used-generate-viewport/page.tsx (9:17) @ generateViewport
diff --git a/test/e2e/app-dir/use-cache/use-cache.test.ts b/test/e2e/app-dir/use-cache/use-cache.test.ts
index 40b4732e5343..8fa465ca2104 100644
--- a/test/e2e/app-dir/use-cache/use-cache.test.ts
+++ b/test/e2e/app-dir/use-cache/use-cache.test.ts
@@ -978,7 +978,7 @@ describe('use-cache', () => {
const expectedErrorMessage = disableJavaScript
? 'Failed to load resource: the server responded with a status of 500 (Internal Server Error)'
: isNextDev
- ? 'Route /draft-mode/[mode] used `cookies()` inside "use cache". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use `cookies()` outside of the cached function and pass the required dynamic data in as an argument. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache'
+ ? 'Route "/draft-mode/[mode]": `cookies()` can\'t be read inside `"use cache"`. Read it outside the cached function and pass what you need as an argument.\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache'
: GENERIC_RSC_ERROR
expect(logs).toMatchObject(