diff --git a/docs/01-app/03-api-reference/04-functions/unstable_cache.mdx b/docs/01-app/03-api-reference/04-functions/unstable_cache.mdx
index 9cbc399df68a..62c2a120225e 100644
--- a/docs/01-app/03-api-reference/04-functions/unstable_cache.mdx
+++ b/docs/01-app/03-api-reference/04-functions/unstable_cache.mdx
@@ -26,9 +26,22 @@ export default async function Component({ userID }) {
> **Good to know**:
>
-> - Accessing uncached data sources such as `headers` or `cookies` 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 uncached data in as an argument.
+> - Accessing request data such as `headers` or `cookies` inside a cache scope is not supported. Read the data outside the cached function and pass the values you need as arguments.
> - This API uses Next.js' built-in cache to persist the result across requests and deployments. See [Caching and Revalidating](/docs/app/getting-started/caching).
+## Unsupported operations
+
+The function passed to `unstable_cache` cannot depend on the incoming request. Read values from `cookies()` or `headers()` before calling the cached function, then pass those values as arguments so they become part of the cache key.
+
+The cached function also cannot:
+
+- Call `connection()`, which requires an incoming request
+- Enable or disable draft mode
+- Call `revalidateTag()`, `updateTag()`, or `revalidatePath()` during cache execution
+- Call a function that uses the `use cache: private` directive
+
+Perform request-dependent work before calling the cached function. Perform mutations and revalidation afterward from a Server Action or Route Handler.
+
## Parameters
```jsx
diff --git a/errors/cache-life-outside-use-cache.mdx b/errors/cache-life-outside-use-cache.mdx
new file mode 100644
index 000000000000..7450ae6dd1a5
--- /dev/null
+++ b/errors/cache-life-outside-use-cache.mdx
@@ -0,0 +1,44 @@
+---
+title: Cannot call `cacheLife()` outside `use cache`
+---
+
+## Why This Error Occurred
+
+The `cacheLife()` function configures the `stale`, `revalidate`, and `expire` times for a cache entry. Call it from a function or component that uses the `use cache` or `use cache: private` directive. When you call `cacheLife()` outside a cached function, there is no cache entry to configure.
+
+```jsx filename="app/page.js" highlight={4}
+import { cacheLife } from 'next/cache'
+
+export default async function Page() {
+ cacheLife('hours') // No cache entry to configure
+ return
...
+}
+```
+
+## Possible Ways to Fix It
+
+Move `cacheLife()` inside the cached function whose lifetime you want to set.
+
+```jsx filename="app/page.js" highlight={5}
+import { cacheLife } from 'next/cache'
+
+async function getProducts() {
+ 'use cache'
+ cacheLife('hours') // Configures this cache entry
+ return db.products.findMany()
+}
+
+export default async function Page() {
+ const products = await getProducts()
+ return ...
+}
+```
+
+If you don't intend to cache the function or component, remove the `cacheLife()` call.
+
+## Useful Links
+
+- [`cacheLife()` function](/docs/app/api-reference/functions/cacheLife)
+- [`cacheTag()` function](/docs/app/api-reference/functions/cacheTag)
+- [`use cache` directive](/docs/app/api-reference/directives/use-cache)
+- [`use cache: private` directive](/docs/app/api-reference/directives/use-cache-private)
diff --git a/errors/cache-tag-outside-use-cache.mdx b/errors/cache-tag-outside-use-cache.mdx
new file mode 100644
index 000000000000..8ac045e68330
--- /dev/null
+++ b/errors/cache-tag-outside-use-cache.mdx
@@ -0,0 +1,45 @@
+---
+title: Cannot call `cacheTag()` outside `use cache`
+---
+
+## Why This Error Occurred
+
+The `cacheTag()` function attaches one or more tags to a cache entry so you can later revalidate it with `revalidateTag()`. Call it from a function or component that uses the `use cache` or `use cache: private` directive. When you call `cacheTag()` outside a cached function, there is no cache entry to tag.
+
+```jsx filename="app/page.js" highlight={4}
+import { cacheTag } from 'next/cache'
+
+export default async function Page() {
+ cacheTag('products') // No cache entry to tag
+ return ...
+}
+```
+
+## Possible Ways to Fix It
+
+Move `cacheTag()` inside the cached function whose entry you want to tag.
+
+```jsx filename="app/page.js" highlight={5}
+import { cacheTag } from 'next/cache'
+
+async function getProducts() {
+ 'use cache'
+ cacheTag('products') // Tags this cache entry
+ return db.products.findMany()
+}
+
+export default async function Page() {
+ const products = await getProducts()
+ return ...
+}
+```
+
+If you don't intend to cache the function or component, remove the `cacheTag()` call. To revalidate the tag later, call [`revalidateTag()`](/docs/app/api-reference/functions/revalidateTag) from a Server Action or Route Handler.
+
+## Useful Links
+
+- [`cacheTag()` function](/docs/app/api-reference/functions/cacheTag)
+- [`cacheLife()` function](/docs/app/api-reference/functions/cacheLife)
+- [`use cache` directive](/docs/app/api-reference/directives/use-cache)
+- [`use cache: private` directive](/docs/app/api-reference/directives/use-cache-private)
+- [`revalidateTag()` function](/docs/app/api-reference/functions/revalidateTag)
diff --git a/errors/next-request-in-use-cache.mdx b/errors/next-request-in-use-cache.mdx
index 5da10e189a0c..4c8933260f18 100644
--- a/errors/next-request-in-use-cache.mdx
+++ b/errors/next-request-in-use-cache.mdx
@@ -1,46 +1,50 @@
---
-title: Cannot access `cookies()` or `headers()` in `"use cache"`
+title: Cannot access request data in `use cache`
---
## Why This Error Occurred
-A function is trying to read from the current incoming request inside the scope of a function annotated with `"use cache"`. This is not supported because it would make the cache invalidated by every request which is probably not what you intended.
+A cached function tried to access the incoming request. APIs such as `cookies()`, `headers()`, `searchParams`, and `connection()` depend on the request and cannot be called inside a function that uses the `use cache` directive. This error can also occur when you pass unresolved request data into a cached function during prerendering. You can read draft mode inside a cached function, but enable or disable it outside.
+
+A cached function can also stall if it awaits a promise stored outside the function, such as one kept in a module-scoped `Map` for deduplication.
## Possible Ways to Fix It
-Instead of calling this inside the `"use cache"` function, move it outside the function and pass the value in as an argument. The specific value will now be part of the cache key through its arguments.
+Read and resolve request data outside the cached function, then pass only the values you need as arguments. Call `connection()` and enable or disable draft mode outside the cached function as well.
+
+If a module-scoped cache or deduplication layer stores promises, remove it. The `use cache` directive already deduplicates calls with the same arguments within a render pass and across requests for as long as the cache entry lasts.
Before:
```jsx filename="app/page.js" highlight={5}
import { cookies } from 'next/headers'
-async function getExampleData() {
- "use cache"
+async function getGreeting() {
+ 'use cache'
const isLoggedIn = (await cookies()).has('token')
- ...
+ return isLoggedIn ? 'Welcome back' : 'Welcome'
}
export default async function Page() {
- const data = await getExampleData()
- return ...
+ const greeting = await getGreeting()
+ return {greeting}
}
```
After:
-```jsx filename="app/page.js" highlight={9}
+```jsx filename="app/page.js" highlight={9,10}
import { cookies } from 'next/headers'
-async function getExampleData(isLoggedIn) {
- "use cache"
- ...
+async function getGreeting(isLoggedIn) {
+ 'use cache'
+ return isLoggedIn ? 'Welcome back' : 'Welcome'
}
export default async function Page() {
const isLoggedIn = (await cookies()).has('token')
- const data = await getExampleData(isLoggedIn)
- return ...
+ const greeting = await getGreeting(isLoggedIn)
+ return {greeting}
}
```
@@ -48,4 +52,6 @@ export default async function Page() {
- [`headers()` function](/docs/app/api-reference/functions/headers)
- [`cookies()` function](/docs/app/api-reference/functions/cookies)
+- [`connection()` function](/docs/app/api-reference/functions/connection)
- [`draftMode()` function](/docs/app/api-reference/functions/draft-mode)
+- [`use cache` directive](/docs/app/api-reference/directives/use-cache)
diff --git a/errors/revalidate-in-use-cache.mdx b/errors/revalidate-in-use-cache.mdx
new file mode 100644
index 000000000000..6126cb164936
--- /dev/null
+++ b/errors/revalidate-in-use-cache.mdx
@@ -0,0 +1,41 @@
+---
+title: Cannot revalidate during render, inside a cached function, or in `generateStaticParams`
+---
+
+## Why This Error Occurred
+
+The `revalidateTag()` and `revalidatePath()` functions invalidate cached data. To keep cache state consistent, call them from a Server Action or Route Handler. Next.js throws this error when you call either function during rendering, from a cached function, or from `generateStaticParams`.
+
+```jsx filename="app/products/page.js" highlight={5}
+import { revalidateTag } from 'next/cache'
+
+export default async function Page() {
+ const products = await db.products.findMany()
+ revalidateTag('products', 'max') // Cannot revalidate during render
+
+ return {products.length} products
+}
+```
+
+## Possible Ways to Fix It
+
+Call `revalidateTag()` or `revalidatePath()` from the Server Action or Route Handler itself. Do not call either function during rendering or from a function that uses the `use cache` directive or `unstable_cache()`.
+
+```jsx filename="app/actions.js" highlight={6}
+'use server'
+import { revalidateTag } from 'next/cache'
+
+export async function saveProduct(data) {
+ await db.products.create(data)
+ revalidateTag('products', 'max') // Runs outside any cached function
+}
+```
+
+To tag the cache entry that this revalidates, call [`cacheTag()`](/docs/app/api-reference/functions/cacheTag) inside the function that uses the `use cache` directive to read the data.
+
+## Useful Links
+
+- [`revalidateTag()` function](/docs/app/api-reference/functions/revalidateTag)
+- [`revalidatePath()` function](/docs/app/api-reference/functions/revalidatePath)
+- [Revalidating data](/docs/app/getting-started/revalidating)
+- [`use cache` directive](/docs/app/api-reference/directives/use-cache)
diff --git a/errors/use-cache-private-composition.mdx b/errors/use-cache-private-composition.mdx
new file mode 100644
index 000000000000..49844b338c09
--- /dev/null
+++ b/errors/use-cache-private-composition.mdx
@@ -0,0 +1,46 @@
+---
+title: 'Invalid `use cache: private` composition'
+---
+
+## Why This Error Occurred
+
+The `use cache: private` directive lets a cached function access request-specific data. Next.js stores its results only in the browser's memory. Private cached functions cannot run inside shared caches or without an active request. This error occurs when a private cached function is:
+
+- **Nested inside a public `use cache` directive.** A shared cached function can reuse its result across users, so it cannot contain a private cached function. Nest a private cached function only inside another private cached function.
+- **Used inside `unstable_cache()`.** `unstable_cache()` is a shared cache and has the same restriction.
+- **Used without an active request.** A private cached function depends on the current request, so it cannot run during build-time contexts such as `generateStaticParams`.
+
+```jsx filename="app/page.js" highlight={2,7}
+async function PrivateSegment() {
+ 'use cache: private'
+ return Private
+}
+
+export default async function Page() {
+ 'use cache' // A public cache cannot contain a private one
+ return
+}
+```
+
+## Possible Ways to Fix It
+
+Nest a private cached function only inside another private cached function. You can also call it directly from a component or function that runs during a request. Do not place it inside a public cached function, `unstable_cache()`, or a build-time context.
+
+```jsx filename="app/page.js" highlight={7}
+async function PrivateSegment() {
+ 'use cache: private'
+ return Private
+}
+
+export default async function Page() {
+ // No surrounding "use cache". The private segment runs per request.
+ return
+}
+```
+
+If the data is the same for every user, use the `use cache` directive so Next.js can prerender and reuse the result. If you need per-user data, read it during the request instead of in `generateStaticParams`.
+
+## Useful Links
+
+- [`use cache: private` directive](/docs/app/api-reference/directives/use-cache-private)
+- [`use cache` directive](/docs/app/api-reference/directives/use-cache)
diff --git a/evals/evals/agent-043-view-transitions/EVAL.ts b/evals/evals/agent-043-view-transitions/EVAL.ts
index 9898090f8840..10735edebd7c 100644
--- a/evals/evals/agent-043-view-transitions/EVAL.ts
+++ b/evals/evals/agent-043-view-transitions/EVAL.ts
@@ -5,8 +5,11 @@
* product gallery app covering shared element morphs, directional navigation,
* Suspense reveal animations, and accessibility.
*
+ * View transitions need no next.config flag: experimental.viewTransition was
+ * inert and removed in #96098, and the docs now say "works with no
+ * configuration" — so nothing here may grade the config either way.
+ *
* Tricky because agents may:
- * - Not know about the experimental.viewTransition flag in next.config
* - Try to call document.startViewTransition manually instead of using
* React's component
* - Import ViewTransition from a third-party library instead of 'react'
@@ -73,17 +76,6 @@ function readAllCssFiles(): string {
return unique.map((f) => readFileSync(f, 'utf-8')).join('\n')
}
-test('next.config enables viewTransition', () => {
- const configPath = existsSync(join(process.cwd(), 'next.config.ts'))
- ? 'next.config.ts'
- : 'next.config.js'
- const content = stripComments(
- readFileSync(join(process.cwd(), configPath), 'utf-8')
- )
-
- expect(content).toMatch(/viewTransition\s*:\s*true/)
-})
-
test('ViewTransition is imported from react', () => {
const allSource = readAllSourceFiles()
diff --git a/lerna.json b/lerna.json
index ce45004383c1..d8bda8c8aadc 100644
--- a/lerna.json
+++ b/lerna.json
@@ -15,5 +15,5 @@
"registry": "https://registry.npmjs.org/"
}
},
- "version": "16.4.0-canary.12"
+ "version": "16.4.0-canary.13"
}
\ No newline at end of file
diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json
index a7d93b3378b3..0170e8b2698d 100644
--- a/packages/create-next-app/package.json
+++ b/packages/create-next-app/package.json
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"keywords": [
"react",
"next",
diff --git a/packages/devlow-bench/package.json b/packages/devlow-bench/package.json
index 278791a560a2..01e7daf053a5 100644
--- a/packages/devlow-bench/package.json
+++ b/packages/devlow-bench/package.json
@@ -1,7 +1,7 @@
{
"name": "@vercel/devlow-bench",
"private": true,
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"description": "Benchmarking tool for the developer workflow",
"repository": {
"type": "git",
diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json
index 96bda10dceb1..99167e1361af 100644
--- a/packages/eslint-config-next/package.json
+++ b/packages/eslint-config-next/package.json
@@ -1,6 +1,6 @@
{
"name": "eslint-config-next",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"description": "ESLint configuration used by Next.js.",
"license": "MIT",
"repository": {
@@ -12,7 +12,7 @@
"dist"
],
"dependencies": {
- "@next/eslint-plugin-next": "16.4.0-canary.12",
+ "@next/eslint-plugin-next": "16.4.0-canary.13",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.32.0",
diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json
index e832bee46979..5ea9085fc54d 100644
--- a/packages/eslint-plugin-internal/package.json
+++ b/packages/eslint-plugin-internal/package.json
@@ -1,7 +1,7 @@
{
"name": "@next/eslint-plugin-internal",
"private": true,
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"description": "ESLint plugin for working on Next.js.",
"exports": {
".": "./src/eslint-plugin-internal.js"
diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json
index 13c1e6981a67..fcacc7ceb566 100644
--- a/packages/eslint-plugin-next/package.json
+++ b/packages/eslint-plugin-next/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/eslint-plugin-next",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"description": "ESLint plugin for Next.js.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
diff --git a/packages/font/package.json b/packages/font/package.json
index 1355675c43fd..4d70e2f680a9 100644
--- a/packages/font/package.json
+++ b/packages/font/package.json
@@ -1,7 +1,7 @@
{
"name": "@next/font",
"private": true,
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"repository": {
"url": "vercel/next.js",
"directory": "packages/font"
diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json
index e8ef9d3c78d9..bfcf5c0c89c0 100644
--- a/packages/next-bundle-analyzer/package.json
+++ b/packages/next-bundle-analyzer/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"main": "index.js",
"types": "index.d.ts",
"license": "MIT",
diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json
index 7699e53e234c..2556233cb123 100644
--- a/packages/next-codemod/package.json
+++ b/packages/next-codemod/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/codemod",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"license": "MIT",
"repository": {
"type": "git",
diff --git a/packages/next-env/package.json b/packages/next-env/package.json
index 55760b7c0128..d865cc9213dd 100644
--- a/packages/next-env/package.json
+++ b/packages/next-env/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/env",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"keywords": [
"react",
"next",
diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json
index 79d4194f2795..bfbdb6799944 100644
--- a/packages/next-mdx/package.json
+++ b/packages/next-mdx/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/mdx",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"main": "index.js",
"license": "MIT",
"repository": {
diff --git a/packages/next-playwright/package.json b/packages/next-playwright/package.json
index d0ffb88ba5dd..d0faf73cabf1 100644
--- a/packages/next-playwright/package.json
+++ b/packages/next-playwright/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/playwright",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-playwright"
diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json
index 73d5301bca78..0eb292f5d323 100644
--- a/packages/next-plugin-storybook/package.json
+++ b/packages/next-plugin-storybook/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-storybook",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-storybook"
diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json
index 7abe71b873d7..076c6d07be59 100644
--- a/packages/next-polyfill-module/package.json
+++ b/packages/next-polyfill-module/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-module",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)",
"main": "dist/polyfill-module.js",
"license": "MIT",
diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json
index d645bb7fe025..166ae464fa1f 100644
--- a/packages/next-polyfill-nomodule/package.json
+++ b/packages/next-polyfill-nomodule/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-nomodule",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"description": "A polyfill for non-dead, nomodule browsers.",
"main": "dist/polyfill-nomodule.js",
"license": "MIT",
diff --git a/packages/next-routing/package.json b/packages/next-routing/package.json
index 0d853f3110fe..8c948c18dad2 100644
--- a/packages/next-routing/package.json
+++ b/packages/next-routing/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/routing",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"keywords": [
"react",
"next",
diff --git a/packages/next-rspack/package.json b/packages/next-rspack/package.json
index 5a5e7d653375..afd9ae7774c1 100644
--- a/packages/next-rspack/package.json
+++ b/packages/next-rspack/package.json
@@ -1,6 +1,6 @@
{
"name": "next-rspack",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-rspack"
diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json
index c715085c9102..9157d61808d4 100644
--- a/packages/next-swc/package.json
+++ b/packages/next-swc/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/swc",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"private": true,
"files": [
"native/"
diff --git a/packages/next/package.json b/packages/next/package.json
index d636ff0b9879..104bc1c724d1 100644
--- a/packages/next/package.json
+++ b/packages/next/package.json
@@ -1,6 +1,6 @@
{
"name": "next",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"description": "The React Framework",
"main": "./dist/server/next.js",
"license": "MIT",
@@ -100,7 +100,7 @@
]
},
"dependencies": {
- "@next/env": "16.4.0-canary.12",
+ "@next/env": "16.4.0-canary.13",
"@swc/helpers": "0.5.23",
"baseline-browser-mapping": "^2.9.19",
"caniuse-lite": "^1.0.30001579",
@@ -164,11 +164,11 @@
"@modelcontextprotocol/sdk": "1.18.1",
"@mswjs/interceptors": "0.42.0",
"@napi-rs/triples": "1.2.0",
- "@next/font": "16.4.0-canary.12",
- "@next/polyfill-module": "16.4.0-canary.12",
- "@next/polyfill-nomodule": "16.4.0-canary.12",
- "@next/react-refresh-utils": "16.4.0-canary.12",
- "@next/swc": "16.4.0-canary.12",
+ "@next/font": "16.4.0-canary.13",
+ "@next/polyfill-module": "16.4.0-canary.13",
+ "@next/polyfill-nomodule": "16.4.0-canary.13",
+ "@next/react-refresh-utils": "16.4.0-canary.13",
+ "@next/swc": "16.4.0-canary.13",
"@opentelemetry/api": "1.6.0",
"@playwright/test": "1.61.0",
"@rspack/core": "1.6.7",
diff --git a/packages/next/src/server/request/connection.ts b/packages/next/src/server/request/connection.ts
index 47579b9f9161..eb902b15bc87 100644
--- a/packages/next/src/server/request/connection.ts
+++ b/packages/next/src/server/request/connection.ts
@@ -16,6 +16,11 @@ import { isRequestApiAllowedInCurrentPhase } 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.
@@ -49,9 +54,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
@@ -61,18 +64,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 3ddd8c223b41..37875657b934 100644
--- a/packages/next/src/server/request/cookies.ts
+++ b/packages/next/src/server/request/cookies.ts
@@ -28,6 +28,10 @@ import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-b
import { isRequestApiAllowedInCurrentPhase } from './utils'
import { applyOwnerStack } from '../dynamic-rendering-utils'
import { InvariantError } from '../../shared/lib/invariant-error'
+import {
+ createCookiesInUseCacheError,
+ createCookiesInUnstableCacheError,
+} from '../use-cache/use-cache-messages'
export function cookies(): Promise {
const callingExpression = 'cookies'
@@ -57,17 +61,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 68531e3dd182..f3e84ef552d2 100644
--- a/packages/next/src/server/request/draft-mode.ts
+++ b/packages/next/src/server/request/draft-mode.ts
@@ -18,6 +18,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,
@@ -210,8 +214,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)
@@ -219,8 +224,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 bb587fa0399b..ec0696d1b328 100644
--- a/packages/next/src/server/request/headers.ts
+++ b/packages/next/src/server/request/headers.ts
@@ -26,6 +26,10 @@ import { createDedupedByCallsiteServerErrorLoggerDev } from '../create-deduped-b
import { isRequestApiAllowedInCurrentPhase } from './utils'
import { applyOwnerStack } from '../dynamic-rendering-utils'
import { InvariantError } from '../../shared/lib/invariant-error'
+import {
+ createHeadersInUseCacheError,
+ createHeadersInUnstableCacheError,
+} from '../use-cache/use-cache-messages'
/**
* This function allows you to read the HTTP incoming request headers in
@@ -58,18 +62,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 af8b467790af..20ce8cd61e25 100644
--- a/packages/next/src/server/request/utils.ts
+++ b/packages/next/src/server/request/utils.ts
@@ -2,6 +2,7 @@ import { StaticGenBailoutError } from '../../client/components/static-generation
import { actionAsyncStorage } from '../app-render/action-async-storage.external'
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'
import type { WorkUnitStore } from '../app-render/work-unit-async-storage.external'
export function throwWithStaticGenerationBailoutErrorWithDynamicError(
@@ -17,9 +18,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 243406d5b762..d5706e9eb14a 100644
--- a/packages/next/src/server/route-modules/app-route/module.ts
+++ b/packages/next/src/server/route-modules/app-route/module.ts
@@ -92,6 +92,10 @@ import { trackPendingModules } from '../../app-render/module-loading/track-modul
import { InvariantError } from '../../../shared/lib/invariant-error'
import { LazyModule } from '../../lib/lazy-module'
import { createPrerenderResumeDataCache } from '../../resume-data-cache/resume-data-cache'
+import {
+ createRouteHandlerRequestInUseCacheError,
+ createRouteHandlerRequestInUnstableCacheError,
+} from '../../use-cache/use-cache-messages'
export class WrappedNextRouterError {
constructor(
@@ -1462,12 +1466,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 aec676a42fb8..12afae94351e 100644
--- a/packages/next/src/server/use-cache/cache-life.ts
+++ b/packages/next/src/server/use-cache/cache-life.ts
@@ -1,5 +1,6 @@
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'
import { validateAndNormalizeCacheLifeProfile } from './cache-life-profile'
import type { CacheLife } from './cache-life-profile'
@@ -42,8 +43,8 @@ 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(
+ workAsyncStorage.getStore()?.route
)
case 'cache':
case 'private-cache':
diff --git a/packages/next/src/server/use-cache/cache-tag.ts b/packages/next/src/server/use-cache/cache-tag.ts
index 001bafb10c13..c4a04b4cabeb 100644
--- a/packages/next/src/server/use-cache/cache-tag.ts
+++ b/packages/next/src/server/use-cache/cache-tag.ts
@@ -1,5 +1,7 @@
+import { workAsyncStorage } from '../app-render/work-async-storage.external'
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) {
@@ -20,8 +22,8 @@ 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(
+ workAsyncStorage.getStore()?.route
)
case 'cache':
case 'private-cache':
diff --git a/packages/next/src/server/use-cache/use-cache-errors.ts b/packages/next/src/server/use-cache/use-cache-errors.ts
index 16b8dc7e803f..a18c089de5bd 100644
--- a/packages/next/src/server/use-cache/use-cache-errors.ts
+++ b/packages/next/src/server/use-cache/use-cache-errors.ts
@@ -1,15 +1,17 @@
export class UseCacheTimeoutError extends Error {
- constructor() {
+ constructor(route: string) {
super(
- 'Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".'
+ `Route "${route}": ` +
+ `A \`"use cache"\` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as \`params\` or \`searchParams\`, into the cached function. Resolve the data before calling the function and pass only the values you need.\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache`
)
}
}
export class UseCacheDeadlockError extends Error {
- constructor() {
+ constructor(route: string) {
super(
- 'Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the same server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.'
+ `Route "${route}": ` +
+ `A \`"use cache"\` function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level \`Map\` used to dedupe fetches) is most likely blocking it. \`"use cache"\` already dedupes calls with the same arguments. Remove the surrounding dedupe layer.\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache`
)
}
}
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..4a972808d8f2
--- /dev/null
+++ b/packages/next/src/server/use-cache/use-cache-messages.ts
@@ -0,0 +1,199 @@
+/**
+ * Centralized error factories for cached function and revalidation misuse.
+ * State the scope and constraint, explain non-obvious boundaries, give the
+ * immediate fix, then link to the relevant docs.
+ */
+
+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 USE_CACHE_PRIVATE_API_DOCS =
+ 'https://nextjs.org/docs/app/api-reference/directives/use-cache-private'
+
+const CACHE_TAG_OUTSIDE_USE_CACHE =
+ 'https://nextjs.org/docs/messages/cache-tag-outside-use-cache'
+
+const CACHE_LIFE_OUTSIDE_USE_CACHE =
+ 'https://nextjs.org/docs/messages/cache-life-outside-use-cache'
+
+const USE_CACHE_PRIVATE_COMPOSITION =
+ 'https://nextjs.org/docs/messages/use-cache-private-composition'
+
+const REVALIDATE_IN_USE_CACHE =
+ 'https://nextjs.org/docs/messages/revalidate-in-use-cache'
+
+const NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE =
+ 'https://nextjs.org/docs/messages/nested-use-cache-no-explicit-cachelife'
+
+// Request data accessed in caches
+
+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 called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.\nLearn more: ${NEXT_REQUEST_IN_USE_CACHE}`
+ )
+}
+
+export function createConnectionInPrivateUseCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`connection()\` can't be called inside \`"use cache: private"\` because private cached functions may run during prefetching, without a navigation request. Call it outside the cached function.\nLearn more: ${USE_CACHE_PRIVATE_API_DOCS}`
+ )
+}
+
+export function createConnectionInUnstableCacheError(route: string): Error {
+ return new Error(
+ `Route "${route}": \`connection()\` can't be called inside \`unstable_cache()\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.\nLearn more: ${UNSTABLE_CACHE_API_DOCS}`
+ )
+}
+
+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}`
+ )
+}
+
+// Mutations inside caches and render
+
+/**
+ * Used when `draftMode().enable()` or `.disable()` is called inside
+ * `"use cache"` or `"use cache: private"`. Reading `draftMode()` is fine
+ * inside a cached function, but 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 inside 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 inside a cached function, but enabling or disabling it must happen outside.\nLearn more: ${UNSTABLE_CACHE_API_DOCS}`
+ )
+}
+
+export function createRevalidateDuringRenderError(
+ route: string,
+ expression: string
+): Error {
+ return new Error(
+ `Route "${route}": \`${expression}\` can't be called during render, inside a cached function, or inside \`generateStaticParams\`. Call it from a Server Action or Route Handler instead.\nLearn more: ${REVALIDATE_IN_USE_CACHE}`
+ )
+}
+
+// Cache configuration and nesting
+
+function routePrefix(route: string | undefined): string {
+ return route === undefined ? '' : `Route "${route}": `
+}
+
+export function createCacheTagOutsideUseCacheError(
+ route: string | undefined
+): Error {
+ return new Error(
+ `${routePrefix(route)}\`cacheTag()\` can only be called inside a \`"use cache"\` or \`"use cache: private"\` function.\nLearn more: ${CACHE_TAG_OUTSIDE_USE_CACHE}`
+ )
+}
+
+export function createCacheLifeOutsideUseCacheError(
+ route: string | undefined
+): Error {
+ return new Error(
+ `${routePrefix(route)}\`cacheLife()\` can only be called inside a \`"use cache"\` or \`"use cache: private"\` function.\nLearn more: ${CACHE_LIFE_OUTSIDE_USE_CACHE}`
+ )
+}
+
+export function createNestedCacheZeroRevalidateError(
+ route: string,
+ cause: Error | undefined
+): Error {
+ return new Error(
+ `Route "${route}": 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 whether to prerender it with a non-zero \`revalidate\` or keep it dynamic with \`revalidate: 0\`.\nLearn more: ${NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE}`,
+ { cause }
+ )
+}
+
+export function createNestedCacheShortExpireError(
+ route: string,
+ cause: Error | undefined
+): Error {
+ return new Error(
+ `Route "${route}": 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 whether to prerender it with a longer \`expire\` or keep it dynamic with a short \`expire\`.\nLearn more: ${NESTED_USE_CACHE_NO_EXPLICIT_CACHELIFE}`,
+ { cause }
+ )
+}
+
+// Private cache composition and request context
+
+export function createUseCachePrivateInsidePublicUseCacheError(
+ route: string
+): Error {
+ return new Error(
+ `Route "${route}": \`"use cache: private"\` can't be nested inside \`"use cache"\` because a shared cached function can't depend on private request data. Nest it only inside another \`"use cache: private"\`.\nLearn more: ${USE_CACHE_PRIVATE_COMPOSITION}`
+ )
+}
+
+export function createUseCachePrivateInsideUnstableCacheError(
+ route: string
+): Error {
+ return new Error(
+ `Route "${route}": \`"use cache: private"\` can't be used inside \`unstable_cache()\` because \`unstable_cache()\` uses a shared cache that can't contain private request data. Call the private cached function outside \`unstable_cache()\`.\nLearn more: ${USE_CACHE_PRIVATE_COMPOSITION}`
+ )
+}
+
+export function createUseCachePrivateOutsideRequestContextError(
+ route: string
+): Error {
+ return new Error(
+ `Route "${route}": \`"use cache: private"\` needs an active request, so it can't be used during \`generateStaticParams\` or other build-time contexts. Move it to a request-time component or function.\nLearn more: ${USE_CACHE_PRIVATE_COMPOSITION}`
+ )
+}
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 6a873503938a..ac70b2895356 100644
--- a/packages/next/src/server/use-cache/use-cache-wrapper.ts
+++ b/packages/next/src/server/use-cache/use-cache-wrapper.ts
@@ -94,6 +94,13 @@ import {
UseCacheDeadlockError,
UseCacheTimeoutError,
} from './use-cache-errors'
+import {
+ createNestedCacheShortExpireError,
+ createNestedCacheZeroRevalidateError,
+ createUseCachePrivateInsidePublicUseCacheError,
+ createUseCachePrivateInsideUnstableCacheError,
+ createUseCachePrivateOutsideRequestContextError,
+} from './use-cache-messages'
import {
createHangingInputAbortSignal,
throwToInterruptStaticGeneration,
@@ -360,22 +367,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
@@ -1826,7 +1817,7 @@ export async function cache(
}
}
- const timeoutError = new UseCacheTimeoutError()
+ const timeoutError = new UseCacheTimeoutError(workStore.route)
Error.captureStackTrace(timeoutError, cache)
applyOwnerStack(timeoutError)
@@ -1838,7 +1829,7 @@ export async function cache(
// gate lets the error class drop out of the production runtime bundle.
let deadlockError: UseCacheDeadlockError | undefined
if (process.env.__NEXT_DEV_SERVER) {
- deadlockError = new UseCacheDeadlockError()
+ deadlockError = new UseCacheDeadlockError(workStore.route)
Error.captureStackTrace(deadlockError, cache)
applyOwnerStack(deadlockError)
}
@@ -1885,18 +1876,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(workStore.route)
)
}
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(workStore.route)
)
}
case 'request':
@@ -1913,10 +1898,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(workStore.route)
)
default:
workUnitStore satisfies never
@@ -2415,9 +2397,10 @@ export async function cache(
shouldReportNestedCacheError
) {
throw wrapAsInvalidDynamicUsageError(
- new Error(nestedCacheZeroRevalidateErrorMessage, {
- cause: rdcResult.dynamicNestedCacheError,
- })
+ createNestedCacheZeroRevalidateError(
+ workStore.route,
+ rdcResult.dynamicNestedCacheError
+ )
)
}
debug?.(
@@ -2432,9 +2415,10 @@ export async function cache(
shouldReportNestedCacheError
) {
throw wrapAsInvalidDynamicUsageError(
- new Error(nestedCacheShortExpireErrorMessage, {
- cause: rdcResult.dynamicNestedCacheError,
- })
+ createNestedCacheShortExpireError(
+ workStore.route,
+ rdcResult.dynamicNestedCacheError
+ )
)
}
debug?.(
@@ -2481,9 +2465,10 @@ export async function cache(
shouldReportNestedCacheError
) {
throw wrapAsInvalidDynamicUsageError(
- new Error(nestedCacheZeroRevalidateErrorMessage, {
- cause: rdcResult.dynamicNestedCacheError,
- })
+ createNestedCacheZeroRevalidateError(
+ workStore.route,
+ rdcResult.dynamicNestedCacheError
+ )
)
}
if (
@@ -2492,9 +2477,10 @@ export async function cache(
shouldReportNestedCacheError
) {
throw wrapAsInvalidDynamicUsageError(
- new Error(nestedCacheShortExpireErrorMessage, {
- cause: rdcResult.dynamicNestedCacheError,
- })
+ createNestedCacheShortExpireError(
+ workStore.route,
+ rdcResult.dynamicNestedCacheError
+ )
)
}
// A short-lived entry is a dynamic hole, excluded from the
diff --git a/packages/next/src/server/web/spec-extension/revalidate.ts b/packages/next/src/server/web/spec-extension/revalidate.ts
index 1ed4b33a16c6..3af8de6a13d0 100644
--- a/packages/next/src/server/web/spec-extension/revalidate.ts
+++ b/packages/next/src/server/web/spec-extension/revalidate.ts
@@ -14,6 +14,7 @@ import {
} from '../../../shared/lib/action-revalidation-kind'
import { removeTrailingSlash } from '../../../shared/lib/router/utils/remove-trailing-slash'
import { encodeHeaderSafe } from '../../lib/encode-header-safe'
+import { createRevalidateDuringRenderError } from '../../use-cache/use-cache-messages'
import { validateAndNormalizeCacheLifeProfile } from '../../use-cache/cache-life-profile'
type CacheLifeConfig = {
@@ -37,7 +38,11 @@ export function revalidateTag(tag: string, profile: string | CacheLifeConfig) {
} else if (typeof profile === 'object') {
profile = validateAndNormalizeCacheLifeProfile(profile, { kind: 'inline' })
}
- return revalidate([encodeHeaderSafe(tag)], `revalidateTag ${tag}`, profile)
+ return revalidate(
+ [encodeHeaderSafe(tag)],
+ `revalidateTag(${JSON.stringify(tag)})`,
+ profile
+ )
}
/**
@@ -59,7 +64,11 @@ export function updateTag(tag: string) {
)
}
// updateTag uses immediate expiration (no profile) without deprecation warning
- return revalidate([encodeHeaderSafe(tag)], `updateTag ${tag}`, undefined)
+ return revalidate(
+ [encodeHeaderSafe(tag)],
+ `updateTag(${JSON.stringify(tag)})`,
+ undefined
+ )
}
/**
@@ -119,7 +128,7 @@ export function revalidatePath(originalPath: string, type?: 'layout' | 'page') {
tags.push(`${NEXT_CACHE_IMPLICIT_TAG_ID}/`)
}
- return revalidate(tags, `revalidatePath ${originalPath}`)
+ return revalidate(tags, `revalidatePath(${JSON.stringify(originalPath)})`)
}
function revalidate(
@@ -137,25 +146,15 @@ function revalidate(
const workUnitStore = workUnitAsyncStorage.getStore()
if (workUnitStore) {
if (workUnitStore.phase === 'render') {
- throw new Error(
- `Route ${store.route} used "${expression}" during render 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 createRevalidateDuringRenderError(store.route, expression)
}
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`
- )
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`
- )
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`
- )
+ throw createRevalidateDuringRenderError(store.route, expression)
case 'prerender':
case 'prerender-runtime':
// cacheComponents Prerender
diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json
index f50cde93478a..e7f4df33494a 100644
--- a/packages/react-refresh-utils/package.json
+++ b/packages/react-refresh-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/react-refresh-utils",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"description": "An experimental package providing utilities for React Refresh.",
"repository": {
"url": "vercel/next.js",
diff --git a/packages/third-parties/package.json b/packages/third-parties/package.json
index 3859fcaaefb9..8f8a3893b435 100644
--- a/packages/third-parties/package.json
+++ b/packages/third-parties/package.json
@@ -1,6 +1,6 @@
{
"name": "@next/third-parties",
- "version": "16.4.0-canary.12",
+ "version": "16.4.0-canary.13",
"repository": {
"url": "vercel/next.js",
"directory": "packages/third-parties"
@@ -26,7 +26,7 @@
"third-party-capital": "1.0.20"
},
"devDependencies": {
- "next": "16.4.0-canary.12",
+ "next": "16.4.0-canary.13",
"outdent": "0.8.0",
"prettier": "2.5.1",
"typescript": "6.0.2"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ed7558316e5b..b3672791afe3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1027,7 +1027,7 @@ importers:
packages/eslint-config-next:
dependencies:
'@next/eslint-plugin-next':
- specifier: 16.4.0-canary.12
+ specifier: 16.4.0-canary.13
version: link:../eslint-plugin-next
eslint:
specifier: '>=9.0.0'
@@ -1110,7 +1110,7 @@ importers:
packages/next:
dependencies:
'@next/env':
- specifier: 16.4.0-canary.12
+ specifier: 16.4.0-canary.13
version: link:../next-env
'@swc/helpers':
specifier: 0.5.23
@@ -1231,19 +1231,19 @@ importers:
specifier: 1.2.0
version: 1.2.0
'@next/font':
- specifier: 16.4.0-canary.12
+ specifier: 16.4.0-canary.13
version: link:../font
'@next/polyfill-module':
- specifier: 16.4.0-canary.12
+ specifier: 16.4.0-canary.13
version: link:../next-polyfill-module
'@next/polyfill-nomodule':
- specifier: 16.4.0-canary.12
+ specifier: 16.4.0-canary.13
version: link:../next-polyfill-nomodule
'@next/react-refresh-utils':
- specifier: 16.4.0-canary.12
+ specifier: 16.4.0-canary.13
version: link:../react-refresh-utils
'@next/swc':
- specifier: 16.4.0-canary.12
+ specifier: 16.4.0-canary.13
version: link:../next-swc
'@opentelemetry/api':
specifier: 1.6.0
@@ -1986,7 +1986,7 @@ importers:
version: 1.0.20
devDependencies:
next:
- specifier: 16.4.0-canary.12
+ specifier: 16.4.0-canary.13
version: link:../next
outdent:
specifier: 0.8.0
diff --git a/test/e2e/app-dir/cache-components-errors/use-cache-private.util.ts b/test/e2e/app-dir/cache-components-errors/use-cache-private.util.ts
index 3cf66f3416e0..a1e834469636 100644
--- a/test/e2e/app-dir/cache-components-errors/use-cache-private.util.ts
+++ b/test/e2e/app-dir/cache-components-errors/use-cache-private.util.ts
@@ -22,34 +22,36 @@ export function registerUseCachePrivateTests(
if (isTurbopack) {
await expect(browser).toDisplayRedbox(`
- {
- "description": ""use cache: private" must not be used within \`unstable_cache()\`.",
- "environmentLabel": "Server",
- "label": "Runtime Error",
- "source": "app/use-cache-private-in-unstable-cache/page.tsx (21:38) @
- > 21 | const getCachedData = unstable_cache(async () => {
- | ^",
- "stack": [
- " app/use-cache-private-in-unstable-cache/page.tsx (21:38)",
- "ComponentWithCachedData app/use-cache-private-in-unstable-cache/page.tsx (16:16)",
- ],
- }
- `)
+ {
+ "description": "Route "/use-cache-private-in-unstable-cache": \`"use cache: private"\` can't be used inside \`unstable_cache()\` because \`unstable_cache()\` uses a shared cache that can't contain private request data. Call the private cached function outside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition",
+ "environmentLabel": "Server",
+ "label": "Runtime Error",
+ "source": "app/use-cache-private-in-unstable-cache/page.tsx (21:38) @
+ > 21 | const getCachedData = unstable_cache(async () => {
+ | ^",
+ "stack": [
+ " app/use-cache-private-in-unstable-cache/page.tsx (21:38)",
+ "ComponentWithCachedData app/use-cache-private-in-unstable-cache/page.tsx (16:16)",
+ ],
+ }
+ `)
} else {
await expect(browser).toDisplayRedbox(`
- {
- "description": ""use cache: private" must not be used within \`unstable_cache()\`.",
- "environmentLabel": "Server",
- "label": "Runtime Error",
- "source": "app/use-cache-private-in-unstable-cache/page.tsx (21:38) @ eval
- > 21 | const getCachedData = unstable_cache(async () => {
- | ^",
- "stack": [
- "eval app/use-cache-private-in-unstable-cache/page.tsx (21:38)",
- "ComponentWithCachedData app/use-cache-private-in-unstable-cache/page.tsx (16:16)",
- ],
- }
- `)
+ {
+ "description": "Route "/use-cache-private-in-unstable-cache": \`"use cache: private"\` can't be used inside \`unstable_cache()\` because \`unstable_cache()\` uses a shared cache that can't contain private request data. Call the private cached function outside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition",
+ "environmentLabel": "Server",
+ "label": "Runtime Error",
+ "source": "app/use-cache-private-in-unstable-cache/page.tsx (21:38) @ eval
+ > 21 | const getCachedData = unstable_cache(async () => {
+ | ^",
+ "stack": [
+ "eval app/use-cache-private-in-unstable-cache/page.tsx (21:38)",
+ "ComponentWithCachedData app/use-cache-private-in-unstable-cache/page.tsx (16:16)",
+ ],
+ }
+ `)
}
})
} else {
@@ -68,7 +70,8 @@ export function registerUseCachePrivateTests(
if (isDebugPrerender) {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within \`unstable_cache()\`.
+ "Error: Route "/use-cache-private-in-unstable-cache": \`"use cache: private"\` can't be used inside \`unstable_cache()\` because \`unstable_cache()\` uses a shared cache that can't contain private request data. Call the private cached function outside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
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 | }
@@ -86,7 +89,8 @@ export function registerUseCachePrivateTests(
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within \`unstable_cache()\`.
+ "Error: Route "/use-cache-private-in-unstable-cache": \`"use cache: private"\` can't be used inside \`unstable_cache()\` because \`unstable_cache()\` uses a shared cache that can't contain private request data. Call the private cached function outside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
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 | }
@@ -106,7 +110,8 @@ export function registerUseCachePrivateTests(
} else {
if (isTurbopack) {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within \`unstable_cache()\`.
+ "Error: Route "/use-cache-private-in-unstable-cache": \`"use cache: private"\` can't be used inside \`unstable_cache()\` because \`unstable_cache()\` uses a shared cache that can't contain private request data. Call the private cached function outside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
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 | }
@@ -124,16 +129,17 @@ export function registerUseCachePrivateTests(
`)
} else {
expect(output).toMatchInlineSnapshot(`
- "Error: "use cache: private" must not be used within \`unstable_cache()\`.
- at a ()
- at b ()
- at c ()
- 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-private-in-unstable-cache" in your browser to investigate the error.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-private-in-unstable-cache". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-private-in-unstable-cache/page: /use-cache-private-in-unstable-cache, exiting the build."
- `)
+ "Error: Route "/use-cache-private-in-unstable-cache": \`"use cache: private"\` can't be used inside \`unstable_cache()\` because \`unstable_cache()\` uses a shared cache that can't contain private request data. Call the private cached function outside \`unstable_cache()\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
+ at a ()
+ at b ()
+ at c ()
+ 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-private-in-unstable-cache" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-private-in-unstable-cache". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-private-in-unstable-cache/page: /use-cache-private-in-unstable-cache, exiting the build."
+ `)
}
}
})
@@ -147,7 +153,8 @@ export function registerUseCachePrivateTests(
await expect(browser).toDisplayRedbox(`
{
- "description": ""use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".",
+ "description": "Route "/use-cache-private-in-use-cache": \`"use cache: private"\` can't be nested inside \`"use cache"\` because a shared cached function can't depend on private request data. Nest it only inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition",
"environmentLabel": "Cache",
"label": "Runtime Error",
"source": "app/use-cache-private-in-use-cache/page.tsx (15:1) @ Private
@@ -176,7 +183,8 @@ export function registerUseCachePrivateTests(
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: Route "/use-cache-private-in-use-cache": \`"use cache: private"\` can't be nested inside \`"use cache"\` because a shared cached function can't depend on private request data. Nest it only inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
at Private (app/use-cache-private-in-use-cache/page.tsx:15:1)
13 | }
14 |
@@ -195,27 +203,29 @@ export function registerUseCachePrivateTests(
`)
} 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".
- at Private (webpack:///app/use-cache-private-in-use-cache/page.tsx:15:1)
- 13 | }
- 14 |
- > 15 | async function Private() {
- | ^
- 16 | 'use cache: private'
- 17 |
- 18 | return Private
{
- digest: ''
- }
- To debug the issue, start the app in development mode by running \`next dev\`, then open "/use-cache-private-in-use-cache" in your browser to investigate the error.
- Error occurred prerendering page "/use-cache-private-in-use-cache". Read more: https://nextjs.org/docs/messages/prerender-error
+ "Error: Route "/use-cache-private-in-use-cache": \`"use cache: private"\` can't be nested inside \`"use cache"\` because a shared cached function can't depend on private request data. Nest it only inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
+ at Private (webpack:///app/use-cache-private-in-use-cache/page.tsx:15:1)
+ 13 | }
+ 14 |
+ > 15 | async function Private() {
+ | ^
+ 16 | 'use cache: private'
+ 17 |
+ 18 | return Private
{
+ digest: ''
+ }
+ To debug the issue, start the app in development mode by running \`next dev\`, then open "/use-cache-private-in-use-cache" in your browser to investigate the error.
+ Error occurred prerendering page "/use-cache-private-in-use-cache". Read more: https://nextjs.org/docs/messages/prerender-error
- > Export encountered errors on 1 path:
- /use-cache-private-in-use-cache/page: /use-cache-private-in-use-cache"
- `)
+ > Export encountered errors on 1 path:
+ \t/use-cache-private-in-use-cache/page: /use-cache-private-in-use-cache"
+ `)
} 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: Route "/use-cache-private-in-use-cache": \`"use cache: private"\` can't be nested inside \`"use cache"\` because a shared cached function can't depend on private request data. Nest it only inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
at (app/use-cache-private-in-use-cache/page.tsx:15:1)
13 | }
14 |
@@ -226,7 +236,8 @@ export function registerUseCachePrivateTests(
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: Route "/use-cache-private-in-use-cache": \`"use cache: private"\` can't be nested inside \`"use cache"\` because a shared cached function can't depend on private request data. Nest it only inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
at (app/use-cache-private-in-use-cache/page.tsx:15:1)
13 | }
14 |
@@ -245,20 +256,22 @@ export function registerUseCachePrivateTests(
`)
} 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".
- at a () {
- digest: ''
- }
- Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
- at b () {
- digest: ''
- }
- 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-private-in-use-cache" in your browser to investigate the error.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-private-in-use-cache". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-private-in-use-cache/page: /use-cache-private-in-use-cache, exiting the build."
- `)
+ "⨯ Error: Route "/use-cache-private-in-use-cache": \`"use cache: private"\` can't be nested inside \`"use cache"\` because a shared cached function can't depend on private request data. Nest it only inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
+ at a () {
+ digest: ''
+ }
+ Error: Route "/use-cache-private-in-use-cache": \`"use cache: private"\` can't be nested inside \`"use cache"\` because a shared cached function can't depend on private request data. Nest it only inside another \`"use cache: private"\`.
+ Learn more: https://nextjs.org/docs/messages/use-cache-private-composition
+ at b () {
+ digest: ''
+ }
+ 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-private-in-use-cache" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-private-in-use-cache". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-private-in-use-cache/page: /use-cache-private-in-use-cache, exiting the build."
+ `)
}
}
})
@@ -428,7 +441,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Route /use-cache-private-connection 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",
+ "description": "Route "/use-cache-private-connection": \`connection()\` can't be called inside \`"use cache: private"\` because private cached functions may run during prefetching, without a navigation request. Call it outside the cached function.
+ Learn more: https://nextjs.org/docs/app/api-reference/directives/use-cache-private",
"environmentLabel": null,
"label": "Runtime Error",
"source": "app/use-cache-private-connection/page.tsx (25:21) @ Private
diff --git a/test/e2e/app-dir/cache-components-errors/use-cache.util.ts b/test/e2e/app-dir/cache-components-errors/use-cache.util.ts
index 677ece0bb6d3..2734d8709d2d 100644
--- a/test/e2e/app-dir/cache-components-errors/use-cache.util.ts
+++ b/test/e2e/app-dir/cache-components-errors/use-cache.util.ts
@@ -20,19 +20,20 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
const browser = await next.browser(pathname)
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-cookies/page.tsx (22:18) @ CookiesReadingComponent
- > 22 | await cookies()
- | ^",
- "stack": [
- "CookiesReadingComponent app/use-cache-cookies/page.tsx (22:18)",
- "Page app/use-cache-cookies/page.tsx (10:7)",
- ],
- }
- `)
+ {
+ "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": "Server",
+ "label": "Console Error",
+ "source": "app/use-cache-cookies/page.tsx (22:18) @ CookiesReadingComponent
+ > 22 | await cookies()
+ | ^",
+ "stack": [
+ "CookiesReadingComponent app/use-cache-cookies/page.tsx (22:18)",
+ "Page app/use-cache-cookies/page.tsx (10:7)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -50,7 +51,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
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.
@@ -68,7 +70,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
`)
} 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 {
@@ -87,7 +90,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
} 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.
@@ -105,15 +109,16 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
`)
} 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
- at a ()
- at b ()
- 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" in your browser to investigate the error.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-cookies". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-cookies/page: /use-cache-cookies, exiting the build."
- `)
+ "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:
+ - Start the app in development mode by running \`next dev\`, then open "/use-cache-cookies" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-cookies". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-cookies/page: /use-cache-cookies, exiting the build."
+ `)
}
}
})
@@ -128,19 +133,20 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
const browser = await next.browser(pathname)
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-draft-mode/page.tsx (20:26) @ DraftModeEnablingComponent
- > 20 | ;(await draftMode()).enable()
- | ^",
- "stack": [
- "DraftModeEnablingComponent app/use-cache-draft-mode/page.tsx (20:26)",
- "Page app/use-cache-draft-mode/page.tsx (9:7)",
- ],
- }
- `)
+ {
+ "description": "Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read inside a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "environmentLabel": "Server",
+ "label": "Console Error",
+ "source": "app/use-cache-draft-mode/page.tsx (20:26) @ DraftModeEnablingComponent
+ > 20 | ;(await draftMode()).enable()
+ | ^",
+ "stack": [
+ "DraftModeEnablingComponent app/use-cache-draft-mode/page.tsx (20:26)",
+ "Page app/use-cache-draft-mode/page.tsx (9:7)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -158,7 +164,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
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 inside 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.
@@ -176,27 +183,29 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
`)
} 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
- 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.
- 19 | try {
- > 20 | ;(await draftMode()).enable()
- | ^
- 21 | } catch {}
- 22 |
- 23 | return null
- To debug the issue, start the app in development mode by running \`next dev\`, then open "/use-cache-draft-mode" in your browser to investigate the error.
- Error occurred prerendering page "/use-cache-draft-mode". Read more: https://nextjs.org/docs/messages/prerender-error
+ "Error: Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read inside 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.
+ 19 | try {
+ > 20 | ;(await draftMode()).enable()
+ | ^
+ 21 | } catch {}
+ 22 |
+ 23 | return null
+ To debug the issue, start the app in development mode by running \`next dev\`, then open "/use-cache-draft-mode" in your browser to investigate the error.
+ Error occurred prerendering page "/use-cache-draft-mode". Read more: https://nextjs.org/docs/messages/prerender-error
- > Export encountered errors on 1 path:
- /use-cache-draft-mode/page: /use-cache-draft-mode"
- `)
+ > Export encountered errors on 1 path:
+ \t/use-cache-draft-mode/page: /use-cache-draft-mode"
+ `)
}
} 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 inside 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 {
@@ -213,14 +222,15 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
`)
} 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
- 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.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-draft-mode". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-draft-mode/page: /use-cache-draft-mode, exiting the build."
- `)
+ "Error: Route "/use-cache-draft-mode": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read inside 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.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-draft-mode". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-draft-mode/page: /use-cache-draft-mode, exiting the build."
+ `)
}
}
})
@@ -235,19 +245,20 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
const browser = await next.browser(pathname)
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-headers/page.tsx (21:18) @ HeadersReadingComponent
- > 21 | await headers()
- | ^",
- "stack": [
- "HeadersReadingComponent app/use-cache-headers/page.tsx (21:18)",
- "Page app/use-cache-headers/page.tsx (10:7)",
- ],
- }
- `)
+ {
+ "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": "Server",
+ "label": "Console Error",
+ "source": "app/use-cache-headers/page.tsx (21:18) @ HeadersReadingComponent
+ > 21 | await headers()
+ | ^",
+ "stack": [
+ "HeadersReadingComponent app/use-cache-headers/page.tsx (21:18)",
+ "Page app/use-cache-headers/page.tsx (10:7)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -265,7 +276,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
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.
@@ -283,7 +295,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
`)
} 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 {
@@ -302,7 +315,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
} 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.
@@ -320,15 +334,16 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
`)
} 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
- at a ()
- at b ()
- 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" in your browser to investigate the error.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-headers". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-headers/page: /use-cache-headers, exiting the build."
- `)
+ "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:
+ - Start the app in development mode by running \`next dev\`, then open "/use-cache-headers" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-headers". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-headers/page: /use-cache-headers, exiting the build."
+ `)
}
}
})
@@ -341,19 +356,20 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
const browser = await next.browser('/use-cache-connection')
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-connection/page.tsx (21:21) @ ConnectionCallingComponent
- > 21 | await connection()
- | ^",
- "stack": [
- "ConnectionCallingComponent app/use-cache-connection/page.tsx (21:21)",
- "Page app/use-cache-connection/page.tsx (10:7)",
- ],
- }
- `)
+ {
+ "description": "Route "/use-cache-connection": \`connection()\` can't be called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "environmentLabel": "Server",
+ "label": "Console Error",
+ "source": "app/use-cache-connection/page.tsx (21:21) @ ConnectionCallingComponent
+ > 21 | await connection()
+ | ^",
+ "stack": [
+ "ConnectionCallingComponent app/use-cache-connection/page.tsx (21:21)",
+ "Page app/use-cache-connection/page.tsx (10:7)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -371,7 +387,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
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 called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ 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.
@@ -389,7 +406,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
`)
} 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 called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ 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 {
@@ -408,7 +426,8 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
} 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 called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ 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.
@@ -426,15 +445,16 @@ export function registerUseCacheTests(ctx: CacheComponentsErrorsContext) {
`)
} 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
- at a ()
- at b ()
- 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" in your browser to investigate the error.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-connection". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-connection/page: /use-cache-connection, exiting the build."
- `)
+ "Error: Route "/use-cache-connection": \`connection()\` can't be called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ 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:
+ - Start the app in development mode by running \`next dev\`, then open "/use-cache-connection" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-connection". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-connection/page: /use-cache-connection, exiting the build."
+ `)
}
}
})
@@ -682,32 +702,33 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
const browser = await next.browser('/use-cache-low-expire/nested')
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "cause": [
- {
- "label": "Caused by: Nested dynamic "use cache"",
- "message": "This "use cache" has a dynamic cache life that was propagated to its parent.",
- "source": "app/use-cache-low-expire/nested/page.tsx (3:1) @ innerCache
- > 3 | async function innerCache() {
- | ^",
- "stack": [
- "innerCache app/use-cache-low-expire/nested/page.tsx (3:1)",
- "outerCache app/use-cache-low-expire/nested/page.tsx (14:10)",
- "Page ",
- ],
- },
- ],
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-low-expire/nested/page.tsx (20:14) @ Page
- > 20 | result = await outerCache()
- | ^",
- "stack": [
- "Page app/use-cache-low-expire/nested/page.tsx (20:14)",
- ],
- }
- `)
+ {
+ "cause": [
+ {
+ "label": "Caused by: Nested dynamic "use cache"",
+ "message": "This "use cache" has a dynamic cache life that was propagated to its parent.",
+ "source": "app/use-cache-low-expire/nested/page.tsx (3:1) @ innerCache
+ > 3 | async function innerCache() {
+ | ^",
+ "stack": [
+ "innerCache app/use-cache-low-expire/nested/page.tsx (3:1)",
+ "outerCache app/use-cache-low-expire/nested/page.tsx (14:10)",
+ "Page ",
+ ],
+ },
+ ],
+ "description": "Route "/use-cache-low-expire/nested": 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 whether to prerender it with a longer \`expire\` or keep it dynamic with a short \`expire\`.
+ 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
+ > 20 | result = await outerCache()
+ | ^",
+ "stack": [
+ "Page app/use-cache-low-expire/nested/page.tsx (20:14)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -725,7 +746,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
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: Route "/use-cache-low-expire/nested": 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 whether to prerender it with a longer \`expire\` or keep it dynamic with a short \`expire\`.
+ 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 {
@@ -754,7 +776,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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: Route "/use-cache-low-expire/nested": 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 whether to prerender it with a longer \`expire\` or keep it dynamic with a short \`expire\`.
+ 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 {
@@ -784,7 +807,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
} 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: Route "/use-cache-low-expire/nested": 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 whether to prerender it with a longer \`expire\` or keep it dynamic with a short \`expire\`.
+ 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 {
@@ -813,19 +837,20 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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
- at a () {
- [cause]: Nested dynamic "use cache": This "use cache" has a dynamic cache life that was propagated to its parent.
- at b ()
- at c ()
- at d ()
- }
- 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-low-expire/nested" in your browser to investigate the error.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-low-expire/nested". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-low-expire/nested/page: /use-cache-low-expire/nested, exiting the build."
- `)
+ "Error: Route "/use-cache-low-expire/nested": 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 whether to prerender it with a longer \`expire\` or keep it dynamic with a short \`expire\`.
+ 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 ()
+ at c ()
+ at d ()
+ }
+ 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-low-expire/nested" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-low-expire/nested". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-low-expire/nested/page: /use-cache-low-expire/nested, exiting the build."
+ `)
}
}
})
@@ -1074,32 +1099,33 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
const browser = await next.browser('/use-cache-revalidate-0/nested')
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "cause": [
- {
- "label": "Caused by: Nested dynamic "use cache"",
- "message": "This "use cache" has a dynamic cache life that was propagated to its parent.",
- "source": "app/use-cache-revalidate-0/nested/page.tsx (3:1) @ innerCache
- > 3 | async function innerCache() {
- | ^",
- "stack": [
- "innerCache app/use-cache-revalidate-0/nested/page.tsx (3:1)",
- "outerCache app/use-cache-revalidate-0/nested/page.tsx (14:10)",
- "Page ",
- ],
- },
- ],
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-revalidate-0/nested/page.tsx (20:14) @ Page
- > 20 | result = await outerCache()
- | ^",
- "stack": [
- "Page app/use-cache-revalidate-0/nested/page.tsx (20:14)",
- ],
- }
- `)
+ {
+ "cause": [
+ {
+ "label": "Caused by: Nested dynamic "use cache"",
+ "message": "This "use cache" has a dynamic cache life that was propagated to its parent.",
+ "source": "app/use-cache-revalidate-0/nested/page.tsx (3:1) @ innerCache
+ > 3 | async function innerCache() {
+ | ^",
+ "stack": [
+ "innerCache app/use-cache-revalidate-0/nested/page.tsx (3:1)",
+ "outerCache app/use-cache-revalidate-0/nested/page.tsx (14:10)",
+ "Page ",
+ ],
+ },
+ ],
+ "description": "Route "/use-cache-revalidate-0/nested": 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 whether to prerender it with a non-zero \`revalidate\` or keep it dynamic with \`revalidate: 0\`.
+ 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
+ > 20 | result = await outerCache()
+ | ^",
+ "stack": [
+ "Page app/use-cache-revalidate-0/nested/page.tsx (20:14)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -1117,7 +1143,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
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: Route "/use-cache-revalidate-0/nested": 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 whether to prerender it with a non-zero \`revalidate\` or keep it dynamic with \`revalidate: 0\`.
+ 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 {
@@ -1146,7 +1173,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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: Route "/use-cache-revalidate-0/nested": 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 whether to prerender it with a non-zero \`revalidate\` or keep it dynamic with \`revalidate: 0\`.
+ 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 {
@@ -1176,7 +1204,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
} 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: Route "/use-cache-revalidate-0/nested": 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 whether to prerender it with a non-zero \`revalidate\` or keep it dynamic with \`revalidate: 0\`.
+ 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 {
@@ -1205,19 +1234,20 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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
- at a () {
- [cause]: Nested dynamic "use cache": This "use cache" has a dynamic cache life that was propagated to its parent.
- at b ()
- at c ()
- at d ()
- }
- 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-revalidate-0/nested" in your browser to investigate the error.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-revalidate-0/nested". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-revalidate-0/nested/page: /use-cache-revalidate-0/nested, exiting the build."
- `)
+ "Error: Route "/use-cache-revalidate-0/nested": 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 whether to prerender it with a non-zero \`revalidate\` or keep it dynamic with \`revalidate: 0\`.
+ 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 ()
+ at c ()
+ at d ()
+ }
+ 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-revalidate-0/nested" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-revalidate-0/nested". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-revalidate-0/nested/page: /use-cache-revalidate-0/nested, exiting the build."
+ `)
}
}
})
@@ -1256,16 +1286,16 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
const browser = await next.browser('/use-cache-params/foo')
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "description": "Next.js encountered runtime data during prerendering.",
- "environmentLabel": "Server",
- "label": "Blocking Route",
- "source": null,
- "stack": [
- "Page [Prerender] ",
- ],
- }
- `)
+ {
+ "description": "Next.js encountered runtime data during prerendering.",
+ "environmentLabel": "Server",
+ "label": "Blocking Route",
+ "source": null,
+ "stack": [
+ "Page [Prerender] ",
+ ],
+ }
+ `)
// The recompute is deliberately delayed so it resolves only after the
// edit's own HMR refresh has re-rendered with the stale fallback
@@ -1511,18 +1541,19 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
const browser = await next.browser('/use-cache-cookies-third-party')
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-cookies-third-party/page.tsx (10:7) @ Page
- > 10 |
- | ^",
- "stack": [
- "Page app/use-cache-cookies-third-party/page.tsx (10:7)",
- ],
- }
- `)
+ {
+ "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": "Server",
+ "label": "Console Error",
+ "source": "app/use-cache-cookies-third-party/page.tsx (10:7) @ Page
+ > 10 |
+ | ^",
+ "stack": [
+ "Page app/use-cache-cookies-third-party/page.tsx (10:7)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -1540,7 +1571,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
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 |
@@ -1557,7 +1589,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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.
@@ -1569,7 +1602,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
} 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 |
@@ -1586,15 +1620,16 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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
- at a ()
- at b ()
- 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.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-cookies-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-cookies-third-party/page: /use-cache-cookies-third-party, exiting the build."
- `)
+ "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:
+ - Start the app in development mode by running \`next dev\`, then open "/use-cache-cookies-third-party" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-cookies-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-cookies-third-party/page: /use-cache-cookies-third-party, exiting the build."
+ `)
}
}
})
@@ -1609,18 +1644,19 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
)
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-draft-mode-third-party/page.tsx (10:7) @ Page
- > 10 |
- | ^",
- "stack": [
- "Page app/use-cache-draft-mode-third-party/page.tsx (10:7)",
- ],
- }
- `)
+ {
+ "description": "Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read inside a cached function, but enabling or disabling it must happen outside.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "environmentLabel": "Server",
+ "label": "Console Error",
+ "source": "app/use-cache-draft-mode-third-party/page.tsx (10:7) @ Page
+ > 10 |
+ | ^",
+ "stack": [
+ "Page app/use-cache-draft-mode-third-party/page.tsx (10:7)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -1638,7 +1674,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
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 inside 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 |
@@ -1655,26 +1692,28 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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
- at Page (webpack:///app/use-cache-draft-mode-third-party/page.tsx:10:7)
- 8 | which triggers an error.
- 9 |
- > 10 |
- | ^
- 11 | >
- 12 | )
- 13 | }
- To debug the issue, 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.
- Error occurred prerendering page "/use-cache-draft-mode-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
+ "Error: Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read inside 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 |
+ > 10 |
+ | ^
+ 11 | >
+ 12 | )
+ 13 | }
+ To debug the issue, 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.
+ Error occurred prerendering page "/use-cache-draft-mode-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
- > Export encountered errors on 1 path:
- /use-cache-draft-mode-third-party/page: /use-cache-draft-mode-third-party"
- `)
+ > Export encountered errors on 1 path:
+ \t/use-cache-draft-mode-third-party/page: /use-cache-draft-mode-third-party"
+ `)
}
} 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 inside 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.
@@ -1684,14 +1723,15 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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
- 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.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-draft-mode-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-draft-mode-third-party/page: /use-cache-draft-mode-third-party, exiting the build."
- `)
+ "Error: Route "/use-cache-draft-mode-third-party": \`draftMode().enable()\` can't be called inside \`"use cache"\`. Draft mode can be read inside 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.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-draft-mode-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-draft-mode-third-party/page: /use-cache-draft-mode-third-party, exiting the build."
+ `)
}
}
})
@@ -1704,18 +1744,19 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
const browser = await next.browser('/use-cache-headers-third-party')
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-headers-third-party/page.tsx (10:7) @ Page
- > 10 |
- | ^",
- "stack": [
- "Page app/use-cache-headers-third-party/page.tsx (10:7)",
- ],
- }
- `)
+ {
+ "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": "Server",
+ "label": "Console Error",
+ "source": "app/use-cache-headers-third-party/page.tsx (10:7) @ Page
+ > 10 |
+ | ^",
+ "stack": [
+ "Page app/use-cache-headers-third-party/page.tsx (10:7)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -1733,7 +1774,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
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 |
@@ -1750,7 +1792,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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.
@@ -1762,7 +1805,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
} 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 |
@@ -1779,15 +1823,16 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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
- at a ()
- at b ()
- 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.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-headers-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-headers-third-party/page: /use-cache-headers-third-party, exiting the build."
- `)
+ "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:
+ - Start the app in development mode by running \`next dev\`, then open "/use-cache-headers-third-party" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-headers-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-headers-third-party/page: /use-cache-headers-third-party, exiting the build."
+ `)
}
}
})
@@ -1802,18 +1847,19 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
)
await expect(browser).toDisplayCollapsedRedbox(`
- {
- "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",
- "environmentLabel": "Server",
- "label": "Console Error",
- "source": "app/use-cache-connection-third-party/page.tsx (10:7) @ Page
- > 10 |
- | ^",
- "stack": [
- "Page app/use-cache-connection-third-party/page.tsx (10:7)",
- ],
- }
- `)
+ {
+ "description": "Route "/use-cache-connection-third-party": \`connection()\` can't be called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
+ "environmentLabel": "Server",
+ "label": "Console Error",
+ "source": "app/use-cache-connection-third-party/page.tsx (10:7) @ Page
+ > 10 |
+ | ^",
+ "stack": [
+ "Page app/use-cache-connection-third-party/page.tsx (10:7)",
+ ],
+ }
+ `)
})
} else {
it('should error the build', async () => {
@@ -1831,7 +1877,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
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 called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ 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 |
@@ -1848,7 +1895,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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 called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ 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.
@@ -1860,7 +1908,8 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
} 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 called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ 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 |
@@ -1877,15 +1926,16 @@ Learn more: https://nextjs.org/docs/messages/blocking-prerender-dynamic`
`)
} 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
- at a ()
- at b ()
- 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.
- - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
- Error occurred prerendering page "/use-cache-connection-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
- Export encountered an error on /use-cache-connection-third-party/page: /use-cache-connection-third-party, exiting the build."
- `)
+ "Error: Route "/use-cache-connection-third-party": \`connection()\` can't be called inside \`"use cache"\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ 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:
+ - Start the app in development mode by running \`next dev\`, then open "/use-cache-connection-third-party" in your browser to investigate the error.
+ - Rerun the production build with \`next build --debug-prerender\` to generate better stack traces.
+ Error occurred prerendering page "/use-cache-connection-third-party". Read more: https://nextjs.org/docs/messages/prerender-error
+ Export encountered an error on /use-cache-connection-third-party/page: /use-cache-connection-third-party, exiting the build."
+ `)
}
}
})
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 5919865cdcc3..dfec254a4e74 100644
--- a/test/e2e/app-dir/dynamic-data/dynamic-data.test.ts
+++ b/test/e2e/app-dir/dynamic-data/dynamic-data.test.ts
@@ -307,7 +307,8 @@ describe('dynamic-data inside cache scope', () => {
try {
await expect(browser).toDisplayRedbox(`
{
- "description": "Route /cookies 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",
+ "description": "Route "/cookies": \`cookies()\` can't be read inside \`unstable_cache()\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
"environmentLabel": "Server",
"label": "Runtime Error",
"source": "app/cookies/page.js (4:40) @ ${isTurbopack ? '' : 'eval'}
@@ -327,7 +328,8 @@ describe('dynamic-data inside cache scope', () => {
try {
await expect(browser).toDisplayRedbox(`
{
- "description": "Route /connection 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",
+ "description": "Route "/connection": \`connection()\` can't be called inside \`unstable_cache()\` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.
+ Learn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
"environmentLabel": "Server",
"label": "Runtime Error",
"source": "app/connection/page.js (4:54) @ ${isTurbopack ? '' : 'eval'}
@@ -347,7 +349,8 @@ describe('dynamic-data inside cache scope', () => {
try {
await expect(browser).toDisplayRedbox(`
{
- "description": "Route /headers 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",
+ "description": "Route "/headers": \`headers()\` can't be read inside \`unstable_cache()\`. Read it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/app/api-reference/functions/unstable_cache",
"environmentLabel": "Server",
"label": "Runtime Error",
"source": "app/headers/page.js (4:40) @ ${isTurbopack ? '' : 'eval'}
@@ -371,13 +374,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 called inside `unstable_cache()` because cached functions may run during prerendering, without an incoming request. Call it outside the cached function.'
)
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/revalidatetag-rsc/revalidatetag-rsc.test.ts b/test/e2e/app-dir/revalidatetag-rsc/revalidatetag-rsc.test.ts
index 65a5fb0e1fee..f115886a664e 100644
--- a/test/e2e/app-dir/revalidatetag-rsc/revalidatetag-rsc.test.ts
+++ b/test/e2e/app-dir/revalidatetag-rsc/revalidatetag-rsc.test.ts
@@ -30,7 +30,7 @@ describe('revalidateTag-rsc', () => {
if (isNextDev) {
await waitForRedbox(browser)
await expect(getRedboxHeader(browser)).resolves.toContain(
- 'Route /revalidate_via_page used "revalidateTag data"'
+ 'Route "/revalidate_via_page": `revalidateTag("data")` can\'t be called during render, inside a cached function, or inside `generateStaticParams`.'
)
} else {
await retry(async () => {
@@ -41,7 +41,7 @@ describe('revalidateTag-rsc', () => {
}
expect(next.cliOutput).toContain(
- 'Route /revalidate_via_page used "revalidateTag data"'
+ 'Route "/revalidate_via_page": `revalidateTag("data")` can\'t be called during render, inside a cached function, or inside `generateStaticParams`. Call it from a Server Action or Route Handler instead.\nLearn more: https://nextjs.org/docs/messages/revalidate-in-use-cache'
)
})
}
diff --git a/test/e2e/app-dir/use-cache-configured-timeout/use-cache-configured-timeout.test.ts b/test/e2e/app-dir/use-cache-configured-timeout/use-cache-configured-timeout.test.ts
index c1959d4fb0fc..858c2c81f884 100644
--- a/test/e2e/app-dir/use-cache-configured-timeout/use-cache-configured-timeout.test.ts
+++ b/test/e2e/app-dir/use-cache-configured-timeout/use-cache-configured-timeout.test.ts
@@ -1,8 +1,12 @@
import { nextTestSetup } from 'e2e-utils'
import stripAnsi from 'strip-ansi'
-const expectedTimeoutErrorMessage =
- 'Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".'
+const timeoutErrorMessage =
+ 'A `"use cache"` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as `params` or `searchParams`, into the cached function. Resolve the data before calling the function and pass only the values you need.\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache'
+
+function expectedTimeoutErrorMessage(route: string) {
+ return `Route "${route}": ${timeoutErrorMessage}`
+}
describe('use-cache-configured-timeout', () => {
const { next, isNextDev, skipped } = nextTestSetup({
@@ -27,7 +31,7 @@ describe('use-cache-configured-timeout', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).not.toContain(expectedTimeoutErrorMessage)
+ expect(cliOutput).not.toContain(timeoutErrorMessage)
})
})
@@ -38,7 +42,8 @@ describe('use-cache-configured-timeout', () => {
await expect(browser).toDisplayRedbox(`
{
- "description": "Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".",
+ "description": "Route "/above-dev-timeout": A \`"use cache"\` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as \`params\` or \`searchParams\`, into the cached function. Resolve the data before calling the function and pass only the values you need.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Cache",
"label": "Runtime Error",
"source": "app/above-dev-timeout/page.tsx (4:1) @ getCachedData
@@ -54,7 +59,9 @@ describe('use-cache-configured-timeout', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(expectedTimeoutErrorMessage)
+ expect(cliOutput).toContain(
+ expectedTimeoutErrorMessage('/above-dev-timeout')
+ )
})
})
} else {
@@ -66,7 +73,7 @@ describe('use-cache-configured-timeout', () => {
// expected
}
- expect(next.cliOutput).toContain(expectedTimeoutErrorMessage)
+ expect(next.cliOutput).toContain(timeoutErrorMessage)
expect(next.cliOutput).toContain(
'Error occurred prerendering page "/below-dev-timeout"'
)
diff --git a/test/e2e/app-dir/use-cache-deadlock-probe/use-cache-deadlock-probe.test.ts b/test/e2e/app-dir/use-cache-deadlock-probe/use-cache-deadlock-probe.test.ts
index df6b7d8a2e29..a97b6fd21f05 100644
--- a/test/e2e/app-dir/use-cache-deadlock-probe/use-cache-deadlock-probe.test.ts
+++ b/test/e2e/app-dir/use-cache-deadlock-probe/use-cache-deadlock-probe.test.ts
@@ -2,11 +2,19 @@ import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
import stripAnsi from 'strip-ansi'
-const expectedTimeoutErrorMessage =
- 'Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".'
+const timeoutErrorMessage =
+ 'A `"use cache"` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as `params` or `searchParams`, into the cached function. Resolve the data before calling the function and pass only the values you need.\\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache'
-const expectedDeadlockMessage =
- 'Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the same server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.'
+const deadlockMessage =
+ 'A `"use cache"` function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level `Map` used to dedupe fetches) is most likely blocking it. `"use cache"` already dedupes calls with the same arguments. Remove the surrounding dedupe layer.\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache'
+
+function expectedTimeoutErrorMessage(route: string) {
+ return `Route "${route}": ${timeoutErrorMessage}`
+}
+
+function expectedDeadlockMessage(route: string) {
+ return `Route "${route}": ${deadlockMessage}`
+}
// TODO: The `'use cache'` deadlock probe is disabled in dev for now. The
// streaming dev render now advances to the dynamic stage without waiting for
@@ -41,7 +49,8 @@ describe.skip('use-cache-deadlock-probe', () => {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the same server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.",
+ "description": "Route "/static": A \`"use cache"\` function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level \`Map\` used to dedupe fetches) is most likely blocking it. \`"use cache"\` already dedupes calls with the same arguments. Remove the surrounding dedupe layer.
+Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/static/page.tsx (6:1) @ getCachedData
@@ -57,7 +66,9 @@ describe.skip('use-cache-deadlock-probe', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedDeadlockMessage}`)
+ expect(cliOutput).toContain(
+ `Error: ${expectedDeadlockMessage('/static')}`
+ )
})
})
@@ -68,7 +79,8 @@ describe.skip('use-cache-deadlock-probe', () => {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the same server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.",
+ "description": "Route "/runtime": A \`"use cache"\` function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level \`Map\` used to dedupe fetches) is most likely blocking it. \`"use cache"\` already dedupes calls with the same arguments. Remove the surrounding dedupe layer.
+Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/runtime/page.tsx (8:1) @ getCachedData
@@ -84,7 +96,9 @@ describe.skip('use-cache-deadlock-probe', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedDeadlockMessage}`)
+ expect(cliOutput).toContain(
+ `Error: ${expectedDeadlockMessage('/runtime')}`
+ )
})
})
@@ -98,12 +112,15 @@ describe.skip('use-cache-deadlock-probe', () => {
await retry(() => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedDeadlockMessage}`)
+ expect(cliOutput).toContain(
+ `Error: ${expectedDeadlockMessage('/static')}`
+ )
}, 30_000)
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the same server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.",
+ "description": "Route "/static": A \`"use cache"\` function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level \`Map\` used to dedupe fetches) is most likely blocking it. \`"use cache"\` already dedupes calls with the same arguments. Remove the surrounding dedupe layer.
+Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/static/page.tsx (6:1) @ getCachedData
@@ -129,12 +146,15 @@ describe.skip('use-cache-deadlock-probe', () => {
await retry(() => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedDeadlockMessage}`)
+ expect(cliOutput).toContain(
+ `Error: ${expectedDeadlockMessage('/runtime')}`
+ )
}, 30_000)
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the same server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.",
+ "description": "Route "/runtime": A \`"use cache"\` function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level \`Map\` used to dedupe fetches) is most likely blocking it. \`"use cache"\` already dedupes calls with the same arguments. Remove the surrounding dedupe layer.
+Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/runtime/page.tsx (8:1) @ getCachedData
@@ -161,8 +181,8 @@ describe.skip('use-cache-deadlock-probe', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).not.toContain(expectedTimeoutErrorMessage)
- expect(cliOutput).not.toContain(expectedDeadlockMessage)
+ expect(cliOutput).not.toContain(timeoutErrorMessage)
+ expect(cliOutput).not.toContain(deadlockMessage)
})
})
@@ -176,7 +196,8 @@ describe.skip('use-cache-deadlock-probe', () => {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".",
+ "description": "Route "/also-hangs": A \`"use cache"\` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as \`params\` or \`searchParams\`, into the cached function. Resolve the data before calling the function and pass only the values you need.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/also-hangs/page.tsx (5:1) @ getCachedData
@@ -192,8 +213,10 @@ describe.skip('use-cache-deadlock-probe', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}`)
- expect(cliOutput).not.toContain(expectedDeadlockMessage)
+ expect(cliOutput).toContain(
+ `Error: ${expectedTimeoutErrorMessage('/also-hangs')}`
+ )
+ expect(cliOutput).not.toContain(deadlockMessage)
})
})
@@ -214,8 +237,8 @@ describe.skip('use-cache-deadlock-probe', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).not.toContain(expectedDeadlockMessage)
- expect(cliOutput).not.toContain(expectedTimeoutErrorMessage)
+ expect(cliOutput).not.toContain(deadlockMessage)
+ expect(cliOutput).not.toContain(timeoutErrorMessage)
})
})
@@ -233,7 +256,8 @@ describe.skip('use-cache-deadlock-probe', () => {
await expect(browser).toDisplayRedbox(`
{
- "description": "Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the same server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.",
+ "description": "Route "/recovery-stuck": A \`"use cache"\` function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level \`Map\` used to dedupe fetches) is most likely blocking it. \`"use cache"\` already dedupes calls with the same arguments. Remove the surrounding dedupe layer.
+Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Cache",
"label": "Runtime Error",
"source": "app/recovery-stuck/page.tsx (24:1) @ getCachedData
@@ -249,8 +273,10 @@ describe.skip('use-cache-deadlock-probe', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedDeadlockMessage}`)
- expect(cliOutput).not.toContain(expectedTimeoutErrorMessage)
+ expect(cliOutput).toContain(
+ `Error: ${expectedDeadlockMessage('/recovery-stuck')}`
+ )
+ expect(cliOutput).not.toContain(timeoutErrorMessage)
})
})
@@ -261,7 +287,8 @@ describe.skip('use-cache-deadlock-probe', () => {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a "use cache" entry appears to be stuck on shared state from the outer render scope. The same function completed when run in isolation, which usually means a module-scoped value (for example a top-level Map used to dedupe fetches) is joining a promise created outside the cache. "use cache" already dedupes calls with the same arguments — within a request and across requests on the same server instance — so the surrounding dedupe layer is both unnecessary and the likely cause. Remove it and rely on "use cache" alone for deduping.",
+ "description": "Route "/private-cookies": A \`"use cache"\` function is awaiting a promise created outside it. The same call completed when run in isolation, so a module-scoped value (often a top-level \`Map\` used to dedupe fetches) is most likely blocking it. \`"use cache"\` already dedupes calls with the same arguments. Remove the surrounding dedupe layer.
+Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/private-cookies/page.tsx (20:1) @ getCachedData
@@ -277,7 +304,9 @@ describe.skip('use-cache-deadlock-probe', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedDeadlockMessage}`)
+ expect(cliOutput).toContain(
+ `Error: ${expectedDeadlockMessage('/private-cookies')}`
+ )
})
})
})
diff --git a/test/e2e/app-dir/use-cache-hanging-inputs/use-cache-hanging-inputs.test.ts b/test/e2e/app-dir/use-cache-hanging-inputs/use-cache-hanging-inputs.test.ts
index 66e971addbcf..a68a0060c064 100644
--- a/test/e2e/app-dir/use-cache-hanging-inputs/use-cache-hanging-inputs.test.ts
+++ b/test/e2e/app-dir/use-cache-hanging-inputs/use-cache-hanging-inputs.test.ts
@@ -10,8 +10,12 @@ import {
} from 'next-test-utils'
import stripAnsi from 'strip-ansi'
-const expectedTimeoutErrorMessage =
- 'Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".'
+const timeoutErrorMessage =
+ 'A `"use cache"` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as `params` or `searchParams`, into the cached function. Resolve the data before calling the function and pass only the values you need.\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache'
+
+function expectedTimeoutErrorMessage(route: string) {
+ return `Route "${route}": ${timeoutErrorMessage}`
+}
describe('use-cache-hanging-inputs', () => {
const { next, isNextDev, skipped } = nextTestSetup({
@@ -42,7 +46,9 @@ describe('use-cache-hanging-inputs', () => {
const errorSource = await getRedboxSource(browser)
expect(errorCount).toBe(1)
- expect(errorDescription).toBe(expectedTimeoutErrorMessage)
+ expect(errorDescription).toBe(
+ expectedTimeoutErrorMessage('/uncached-promise')
+ )
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
@@ -58,7 +64,8 @@ describe('use-cache-hanging-inputs', () => {
13 | return ("
`)
- expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
+ expect(cliOutput)
+ .toContain(`Error: ${expectedTimeoutErrorMessage('/uncached-promise')}
at Foo (app/uncached-promise/page.tsx:10:13)`)
}, 180_000)
})
@@ -80,7 +87,9 @@ describe('use-cache-hanging-inputs', () => {
const errorSource = await getRedboxSource(browser)
expect(errorCount).toBe(1)
- expect(errorDescription).toBe(expectedTimeoutErrorMessage)
+ expect(errorDescription).toBe(
+ expectedTimeoutErrorMessage('/uncached-promise-nested')
+ )
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
@@ -96,7 +105,8 @@ describe('use-cache-hanging-inputs', () => {
19 | return getCachedData(promise)"
`)
- expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
+ expect(cliOutput)
+ .toContain(`Error: ${expectedTimeoutErrorMessage('/uncached-promise-nested')}
at indirection (app/uncached-promise-nested/page.tsx:16:1)
at Page (app/uncached-promise-nested/page.tsx:23:22)`)
}, 180_000)
@@ -122,7 +132,9 @@ describe('use-cache-hanging-inputs', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(errorDescription).toBe(expectedTimeoutErrorMessage)
+ expect(errorDescription).toBe(
+ expectedTimeoutErrorMessage('/bound-args')
+ )
expect(errorSource).toMatchInlineSnapshot(`
"app/bound-args/page.tsx (13:15) @ Foo
@@ -136,7 +148,8 @@ describe('use-cache-hanging-inputs', () => {
16 | return ("
`)
- expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
+ expect(cliOutput)
+ .toContain(`Error: ${expectedTimeoutErrorMessage('/bound-args')}
at Foo (app/bound-args/page.tsx:13:15)`)
}, 180_000)
})
@@ -167,7 +180,7 @@ describe('use-cache-hanging-inputs', () => {
expect(cliOutput).toInclude('Error: kaputt!')
expect(cliOutput).toIncludeRepeated(
- escapeStringRegexp(expectedTimeoutErrorMessage),
+ escapeStringRegexp(timeoutErrorMessage),
4
)
diff --git a/test/e2e/app-dir/use-cache-hanging/use-cache-hanging.test.ts b/test/e2e/app-dir/use-cache-hanging/use-cache-hanging.test.ts
index b8c6de589b55..201a128c9dbc 100644
--- a/test/e2e/app-dir/use-cache-hanging/use-cache-hanging.test.ts
+++ b/test/e2e/app-dir/use-cache-hanging/use-cache-hanging.test.ts
@@ -2,8 +2,12 @@ import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
import stripAnsi from 'strip-ansi'
-const expectedTimeoutErrorMessage =
- 'Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".'
+const timeoutErrorMessage =
+ 'A `"use cache"` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as `params` or `searchParams`, into the cached function. Resolve the data before calling the function and pass only the values you need.\nLearn more: https://nextjs.org/docs/messages/next-request-in-use-cache'
+
+function expectedTimeoutErrorMessage(route: string) {
+ return `Route "${route}": ${timeoutErrorMessage}`
+}
describe('use-cache-hanging', () => {
const { next, isNextDev, skipped, isTurbopack } = nextTestSetup({
@@ -24,7 +28,8 @@ describe('use-cache-hanging', () => {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".",
+ "description": "Route "/static": A \`"use cache"\` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as \`params\` or \`searchParams\`, into the cached function. Resolve the data before calling the function and pass only the values you need.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/static/page.tsx (1:1) @ getCachedData
@@ -40,7 +45,8 @@ describe('use-cache-hanging', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
+ expect(cliOutput)
+ .toContain(`Error: ${expectedTimeoutErrorMessage('/static')}
at getCachedData (app/static/page.tsx:1:1)`)
})
})
@@ -52,7 +58,8 @@ describe('use-cache-hanging', () => {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".",
+ "description": "Route "/runtime": A \`"use cache"\` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as \`params\` or \`searchParams\`, into the cached function. Resolve the data before calling the function and pass only the values you need.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/runtime/page.tsx (4:1) @ getCachedData
@@ -68,7 +75,8 @@ describe('use-cache-hanging', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
+ expect(cliOutput)
+ .toContain(`Error: ${expectedTimeoutErrorMessage('/runtime')}
at getCachedData (app/runtime/page.tsx:4:1)`)
})
})
@@ -83,13 +91,15 @@ describe('use-cache-hanging', () => {
await retry(() => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
+ expect(cliOutput)
+ .toContain(`Error: ${expectedTimeoutErrorMessage('/static')}
at getCachedData (app/static/page.tsx:1:1)`)
}, 20_000)
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".",
+ "description": "Route "/static": A \`"use cache"\` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as \`params\` or \`searchParams\`, into the cached function. Resolve the data before calling the function and pass only the values you need.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/static/page.tsx (1:1) @ getCachedData
@@ -115,13 +125,15 @@ describe('use-cache-hanging', () => {
await retry(() => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).toContain(`Error: ${expectedTimeoutErrorMessage}
+ expect(cliOutput)
+ .toContain(`Error: ${expectedTimeoutErrorMessage('/runtime')}
at getCachedData (app/runtime/page.tsx:4:1)`)
}, 20_000)
await expect(browser).toDisplayCollapsedRedbox(`
{
- "description": "Filling a cache during prerender timed out, likely because request-specific arguments such as params, searchParams, cookies() or dynamic data were used inside "use cache".",
+ "description": "Route "/runtime": A \`"use cache"\` function took too long during prerendering. The most common cause is passing unresolved request-specific arguments, such as \`params\` or \`searchParams\`, into the cached function. Resolve the data before calling the function and pass only the values you need.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
"environmentLabel": "Server",
"label": "Console Error",
"source": "app/runtime/page.tsx (4:1) @ getCachedData
@@ -148,7 +160,7 @@ describe('use-cache-hanging', () => {
const cliOutput = stripAnsi(next.cliOutput.slice(outputIndex))
- expect(cliOutput).not.toContain(expectedTimeoutErrorMessage)
+ expect(cliOutput).not.toContain(timeoutErrorMessage)
})
})
} else {
@@ -162,11 +174,13 @@ describe('use-cache-hanging', () => {
if (isTurbopack) {
expect(next.cliOutput)
- .toContain(`Error: ${expectedTimeoutErrorMessage}
+ .toContain(`Error: ${expectedTimeoutErrorMessage('/static')}
at (app/static/page.tsx:1:1)`)
} else {
// Webpack production builds don't have source maps by default.
- expect(next.cliOutput).toContain(expectedTimeoutErrorMessage)
+ expect(next.cliOutput).toContain(
+ expectedTimeoutErrorMessage('/static')
+ )
}
})
})
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 b956df60b2c4..92d394d585cd 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`
describe('use-cache-search-params', () => {
const { next, isNextDev, skipped } = nextTestSetup({
@@ -30,7 +30,8 @@ describe('use-cache-search-params', () => {
await expect(browser).toDisplayRedbox(`
{
- "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",
+ "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
@@ -60,7 +61,8 @@ describe('use-cache-search-params', () => {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "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",
+ "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
@@ -88,7 +90,8 @@ describe('use-cache-search-params', () => {
await expect(browser).toDisplayCollapsedRedbox(`
{
- "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",
+ "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
@@ -126,7 +129,8 @@ describe('use-cache-search-params', () => {
await expect(browser).toDisplayRedbox(`
{
- "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",
+ "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
@@ -146,7 +150,8 @@ describe('use-cache-search-params', () => {
await expect(browser).toDisplayRedbox(`
{
- "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",
+ "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 32c3157820b5..aab19804cd5c 100644
--- a/test/e2e/app-dir/use-cache/use-cache.test.ts
+++ b/test/e2e/app-dir/use-cache/use-cache.test.ts
@@ -1064,7 +1064,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(