diff --git a/packages/next/errors.json b/packages/next/errors.json index b190b445702e..c745ff7859fc 100644 --- a/packages/next/errors.json +++ b/packages/next/errors.json @@ -1300,5 +1300,27 @@ "1299": "Route \"%s\": Next.js encountered uncached or runtime data during prerendering.\\n\\n\\`fetch(...)\\`, \\`cookies()\\`, \\`headers()\\`, \\`params\\`, \\`searchParams\\`, or \\`connection()\\` accessed outside of \\`\\` prevents the route from being prerendered, blocking the page load and leading to a slower user experience.\\n\\nWays to fix this:\\n - [cache] Cache the data access with \\`\"use cache\"\\`\\n https://nextjs.org/docs/messages/blocking-prerender-dynamic#cache-the-component-or-data\\n - [stream] Provide a placeholder with \\`\\` around the data access\\n https://nextjs.org/docs/messages/blocking-prerender-dynamic#wrap-in-or-move-into-suspense\\n - [cache] If the runtime data is \\`params\\` and they're known, prerender them with \\`generateStaticParams\\`\\n https://nextjs.org/docs/messages/blocking-prerender-runtime#for-known-params-prerender\\n - [block] Set \\`export const unstable_instant = false\\` to silence this warning and allow a blocking route\\n https://nextjs.org/docs/messages/blocking-prerender-dynamic#allow-blocking-route", "1300": "A render that hasn't started yet cannot be abandoned", "1301": "Cannot determine late/early stage before starting the render", - "1302": "Attempted to advance to stage %s but the render is limited to %s" + "1302": "Attempted to advance to stage %s but the render is limited to %s", + "1303": "\\`cacheLife()\\` can only be called inside a \\`\"use cache\"\\` function.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/cacheLife", + "1304": "\\`\"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", + "1305": "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", + "1306": "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", + "1307": "\\`cacheTag()\\` can only be called inside a \\`\"use cache\"\\` function.\\nLearn more: https://nextjs.org/docs/app/api-reference/functions/cacheTag", + "1308": "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", + "1309": "\\`\"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", + "1310": "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", + "1311": "\\`\"use cache: private\"\\` can't be used inside \\`unstable_cache()\\`.\\nLearn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private", + "1312": "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", + "1313": "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", + "1314": "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", + "1315": "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", + "1316": "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", + "1317": "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", + "1318": "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", + "1319": "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", + "1320": "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", + "1321": "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", + "1322": "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", + "1323": "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", + "1324": "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/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 2a84c1a2e994..5017c555094b 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 37738c487709..a5ecd7c536d1 100644 --- a/packages/next/src/server/request/draft-mode.ts +++ b/packages/next/src/server/request/draft-mode.ts @@ -19,6 +19,10 @@ import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-b import { StaticGenBailoutError } from '../../client/components/static-generation-bailout' import { DynamicServerError } from '../../client/components/hooks-server-context' import { InvariantError } from '../../shared/lib/invariant-error' +import { + createDraftModeMutationInUseCacheError, + createDraftModeMutationInUnstableCacheError, +} from '../use-cache/use-cache-messages' import { ReflectAdapter } from '../web/spec-extension/adapters/reflect' import { applyOwnerStack, getRuntimeStage } from '../dynamic-rendering-utils' @@ -209,8 +213,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) @@ -218,8 +223,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 b686aba3085c..2788ef3f5f0b 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..b167ec3393c5 --- /dev/null +++ b/packages/next/src/server/use-cache/use-cache-messages.ts @@ -0,0 +1,206 @@ +/** + * 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 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()` ────────────── + +/** + * 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 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 ─────────────────────── + +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..45e795bc2373 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 { + createNestedCacheShortExpireError, + createNestedCacheZeroRevalidateError, + createUseCachePrivateInsidePublicUseCacheError, + createUseCachePrivateInsideUnstableCacheError, + createUseCachePrivateOutsideRequestContextError, +} 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 @@ -2055,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?.( @@ -2068,9 +2050,9 @@ export async function cache( } else { if (rdcResult.hasExplicitExpire === false) { throw wrapAsInvalidDynamicUsageError( - new Error(nestedCacheShortExpireErrorMessage, { - cause: rdcResult.dynamicNestedCacheError, - }) + createNestedCacheShortExpireError( + rdcResult.dynamicNestedCacheError + ) ) } debug?.( @@ -2107,9 +2089,9 @@ export async function cache( rdcResult.hasExplicitRevalidate === false ) { throw wrapAsInvalidDynamicUsageError( - new Error(nestedCacheZeroRevalidateErrorMessage, { - cause: rdcResult.dynamicNestedCacheError, - }) + createNestedCacheZeroRevalidateError( + rdcResult.dynamicNestedCacheError + ) ) } if ( @@ -2117,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/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` 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 4b9c2552def6..2f51f4b869df 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 @@ -2667,8 +2667,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": "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", "label": "Runtime Error", "source": "app/use-cache-cookies/page.tsx (22:18) @ CookiesReadingComponent @@ -2697,7 +2698,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. @@ -2715,7 +2717,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 { @@ -2734,7 +2737,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. @@ -2752,7 +2756,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: @@ -2776,8 +2781,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": "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", "label": "Runtime Error", "source": "app/use-cache-draft-mode/page.tsx (20:26) @ DraftModeEnablingComponent @@ -2806,7 +2812,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. @@ -2824,7 +2831,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. @@ -2844,7 +2852,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 { @@ -2861,7 +2870,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. @@ -2884,8 +2894,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": "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", "label": "Runtime Error", "source": "app/use-cache-headers/page.tsx (21:18) @ HeadersReadingComponent @@ -2914,7 +2925,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. @@ -2932,7 +2944,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 { @@ -2951,7 +2964,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. @@ -2969,7 +2983,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: @@ -2991,8 +3006,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": "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", "label": "Runtime Error", "source": "app/use-cache-connection/page.tsx (21:21) @ ConnectionCallingComponent @@ -3021,7 +3037,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. @@ -3039,7 +3056,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 { @@ -3058,7 +3076,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. @@ -3076,7 +3095,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: @@ -3373,8 +3393,9 @@ Ways to fix this: ], }, ], - "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": "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", "label": "Console Error", "source": "app/use-cache-low-expire/nested/page.tsx (20:14) @ Page @@ -3402,7 +3423,8 @@ Ways to fix this: 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 { @@ -3431,7 +3453,8 @@ Ways to fix this: `) } 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 { @@ -3461,7 +3484,8 @@ Ways to fix this: } 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 { @@ -3490,7 +3514,8 @@ Ways to fix this: `) } 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 () @@ -3794,8 +3819,9 @@ Ways to fix this: ], }, ], - "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": "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", "label": "Console Error", "source": "app/use-cache-revalidate-0/nested/page.tsx (20:14) @ Page @@ -3823,7 +3849,8 @@ Ways to fix this: 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 { @@ -3852,7 +3879,8 @@ Ways to fix this: `) } 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 { @@ -3882,7 +3910,8 @@ Ways to fix this: } 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 { @@ -3911,7 +3940,8 @@ Ways to fix this: `) } 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 () @@ -4184,8 +4214,9 @@ Ways to fix this: 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": "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", "label": "Runtime Error", "source": "app/use-cache-cookies-third-party/page.tsx (10:7) @ Page @@ -4213,7 +4244,8 @@ Ways to fix this: 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 |

@@ -4230,7 +4262,8 @@ Ways to fix this: `) } 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. @@ -4242,7 +4275,8 @@ Ways to fix this: } 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 |

@@ -4259,7 +4293,8 @@ Ways to fix this: `) } 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: @@ -4283,8 +4318,9 @@ Ways to fix this: 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": "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", "label": "Runtime Error", "source": "app/use-cache-draft-mode-third-party/page.tsx (10:7) @ Page @@ -4312,7 +4348,8 @@ Ways to fix this: 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 |

@@ -4329,7 +4366,8 @@ Ways to fix this: `) } 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 |

@@ -4348,7 +4386,8 @@ Ways to fix this: } 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. @@ -4358,7 +4397,8 @@ Ways to fix this: `) } 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. @@ -4381,8 +4421,9 @@ Ways to fix this: 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": "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", "label": "Runtime Error", "source": "app/use-cache-headers-third-party/page.tsx (10:7) @ Page @@ -4410,7 +4451,8 @@ Ways to fix this: 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 |

@@ -4427,7 +4469,8 @@ Ways to fix this: `) } 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. @@ -4439,7 +4482,8 @@ Ways to fix this: } 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 |

@@ -4456,7 +4500,8 @@ Ways to fix this: `) } 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: @@ -4480,8 +4525,9 @@ Ways to fix this: 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": "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", "label": "Runtime Error", "source": "app/use-cache-connection-third-party/page.tsx (10:7) @ Page @@ -4509,7 +4555,8 @@ Ways to fix this: 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 |

@@ -4526,7 +4573,8 @@ Ways to fix this: `) } 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. @@ -4538,7 +4586,8 @@ Ways to fix this: } 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 |

@@ -4555,7 +4604,8 @@ Ways to fix this: `) } 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: @@ -4583,8 +4633,9 @@ Ways to fix this: if (isTurbopack) { 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) @ @@ -4599,8 +4650,9 @@ Ways to fix this: } 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 @@ -4630,7 +4682,8 @@ Ways to fix this: 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 | } @@ -4648,7 +4701,8 @@ Ways to fix this: `) } 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 | } @@ -4668,7 +4722,8 @@ Ways to fix this: } 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 | } @@ -4686,7 +4741,8 @@ Ways to fix this: `) } 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 () @@ -4711,8 +4767,9 @@ Ways to fix this: 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": "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", "label": "Runtime Error", "source": "app/use-cache-private-in-use-cache/page.tsx (15:1) @ Private @@ -4741,7 +4798,8 @@ Ways to fix this: 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 | @@ -4760,7 +4818,8 @@ Ways to fix this: `) } 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 | @@ -4780,7 +4839,8 @@ Ways to fix this: } 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 | } @@ -4792,7 +4852,8 @@ Ways to fix this: 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 | } @@ -4812,12 +4873,14 @@ Ways to fix this: `) } 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(