Skip to content

errors: centralize and DX-friendly "use cache" error messages#94300

Open
aurorascharff wants to merge 6 commits into
canaryfrom
aurorascharff/use-cache-message-dx
Open

errors: centralize and DX-friendly "use cache" error messages#94300
aurorascharff wants to merge 6 commits into
canaryfrom
aurorascharff/use-cache-message-dx

Conversation

@aurorascharff
Copy link
Copy Markdown
Contributor

@aurorascharff aurorascharff commented Jun 1, 2026

What?

Centralizes all "use cache" error messages into one factory module and rewrites them as short, DX-friendly prose with a Learn more: link. Adds the learn-more URLs that several factories were missing.

Why?

Old wording was paragraph-style and scattered across 9 files. New wording is one short imperative sentence + link, so developers (and agents) get the fix immediately.

How?

  • New packages/next/src/server/use-cache/use-cache-messages.ts with 15 factories, 2 const strings, and 7 docs URLs. All 9 call sites import from here.
  • Pattern: Route "${route}": [api] can't be [verb] inside \"use cache"`. [one-line fix].\nLearn more: ${URL}`.
  • Dev overlay: bumped .error-cause-message bottom margin so chained Caused by: blocks match the outer error's spacing before the code frame.
  • Regenerated errors.json (E1287–E1305).

Verification

Test-app scenarios on the error-messages-overhaul demo: 66-cookies, 67-headers, 68-searchParams, 69-connection, 70-draftMode, 72-nested-zero-revalidate, 73-nested-short-expire, 74-private-in-public, 75-private-in-gsp, 76-cacheTag-outside, 77-cacheLife-outside.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

Stats cancelled

Commit: cc598e5
View workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

Failing test suites

Commit: cc598e5 | About building and testing Next.js

pnpm test-dev test/e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts (job)

  • use-cache-search-params > should show an error when searchParams are used inside of a cached generateMetadata (DD)
  • use-cache-search-params > should show an error when searchParams are used inside of a cached generateViewport (DD)
  • use-cache-search-params > when searchParams are caught inside of "use cache" > should show an error (DD)
  • use-cache-search-params > when searchParams are caught inside of "use cache" > should also show an error after the second reload (DD)
  • use-cache-search-params > when searchParams are used inside of "use cache" > should show an error (DD)
Expand output

● use-cache-search-params › when searchParams are used inside of "use cache" › should show an error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params when searchParams are used inside of "use cache" should show an error 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-used used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-used": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-used/page.tsx (8:17) @ Page
  >  8 |   const param = (await searchParams).foo
       |                 ^",

  32 |
  33 |         if (isCacheComponentsEnabled) {
> 34 |           await expect(browser).toDisplayRedbox(`
     |                                 ^
  35 |            {
  36 |              "code": "E842",
  37 |              "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:34:33)

● use-cache-search-params › when searchParams are caught inside of "use cache" › should show an error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params when searchParams are caught inside of "use cache" should show an error 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-caught used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-caught": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-caught/page.tsx (11:5) @ Page
  > 11 |     param = (await searchParams).foo
       |     ^",

  81 |
  82 |         if (isCacheComponentsEnabled) {
> 83 |           await expect(browser).toDisplayRedbox(`
     |                                 ^
  84 |            {
  85 |              "code": "E842",
  86 |              "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:83:33)

● use-cache-search-params › when searchParams are caught inside of "use cache" › should also show an error after the second reload

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params when searchParams are caught inside of "use cache" should also show an error after the second reload 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-caught used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-caught": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-caught/page.tsx (11:5) @ Page
  > 11 |     param = (await searchParams).foo
       |     ^",

  128 |
  129 |         if (isCacheComponentsEnabled) {
> 130 |           await expect(browser).toDisplayRedbox(`
      |                                 ^
  131 |            {
  132 |              "code": "E842",
  133 |              "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:130:33)

● use-cache-search-params › should show an error when searchParams are used inside of a cached generateMetadata

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params should show an error when searchParams are used inside of a cached generateMetadata 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-used-generate-metadata used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-used-generate-metadata": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-used-generate-metadata/page.tsx (9:17) @ generateMetadata
  >  9 |   const title = (await searchParams).title
       |                 ^",

  185 |
  186 |       if (isCacheComponentsEnabled) {
> 187 |         await expect(browser).toDisplayRedbox(`
      |                               ^
  188 |          {
  189 |            "code": "E842",
  190 |            "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:187:31)

● use-cache-search-params › should show an error when searchParams are used inside of a cached generateViewport

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params should show an error when searchParams are used inside of a cached generateViewport 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-used-generate-viewport used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-used-generate-viewport": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-used-generate-viewport/page.tsx (9:17) @ generateViewport
  >  9 |   const color = (await searchParams).color
       |                 ^",

  224 |
  225 |       if (isCacheComponentsEnabled) {
> 226 |         await expect(browser).toDisplayRedbox(`
      |                               ^
  227 |          {
  228 |            "code": "E842",
  229 |            "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:226:31)

pnpm test-dev test/e2e/app-dir/dynamic-data/dynamic-data.test.ts (job)

  • dynamic-data inside cache scope > displays redbox when accessing dynamic data inside a cache scope (DD)
Expand output

● dynamic-data inside cache scope › displays redbox when accessing dynamic data inside a cache scope

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `dynamic-data inside cache scope displays redbox when accessing dynamic data inside a cache scope 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E846",
-   "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",
+   "code": "E1291",
+   "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) @ eval
  > 4 | const cookies = cache(() => nextCookies())
      |                                        ^",

  310 |       let browser = await next.browser('/cookies')
  311 |       try {
> 312 |         await expect(browser).toDisplayRedbox(`
      |                               ^
  313 |          {
  314 |            "code": "E846",
  315 |            "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",

  at Object.toDisplayRedbox (e2e/app-dir/dynamic-data/dynamic-data.test.ts:312:31)

pnpm test-dev test/e2e/app-dir/dynamic-data/dynamic-data.test.ts (job)

  • dynamic-data inside cache scope > displays redbox when accessing dynamic data inside a cache scope (DD)
Expand output

● dynamic-data inside cache scope › displays redbox when accessing dynamic data inside a cache scope

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `dynamic-data inside cache scope displays redbox when accessing dynamic data inside a cache scope 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E846",
-   "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",
+   "code": "E1291",
+   "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) @ <anonymous>
  > 4 | const cookies = cache(() => nextCookies())
      |                                        ^",

  310 |       let browser = await next.browser('/cookies')
  311 |       try {
> 312 |         await expect(browser).toDisplayRedbox(`
      |                               ^
  313 |          {
  314 |            "code": "E846",
  315 |            "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",

  at Object.toDisplayRedbox (e2e/app-dir/dynamic-data/dynamic-data.test.ts:312:31)

pnpm test-dev test/e2e/app-dir/instant-navigation-testing-api/instant-navigation-testing-api.test.ts (job)

  • instant-navigation-testing-api > renders runtime-prefetched content instantly during navigation (DD)
  • instant-navigation-testing-api > runtime params are excluded from instant shell > does not include cookie values in instant shell during page load (DD)
Expand output

● instant-navigation-testing-api › renders runtime-prefetched content instantly during navigation

locator.waitFor: Timeout 60000ms exceeded.
Call log:
  - waiting for locator('[data-testid="search-param-value"]') to be visible

  105 |         '[data-testid="search-param-value"]'
  106 |       )
> 107 |       await searchParamValue.waitFor({ state: 'visible' })
      |                              ^
  108 |       expect(await searchParamValue.textContent()).toContain(
  109 |         'myParam: testValue'
  110 |       )

  at waitFor (e2e/app-dir/instant-navigation-testing-api/instant-navigation-testing-api.test.ts:107:30)
  at instant (../packages/next-playwright/dist/index.js:50:16)
  at Object.<anonymous> (e2e/app-dir/instant-navigation-testing-api/instant-navigation-testing-api.test.ts:99:5)

● instant-navigation-testing-api › runtime params are excluded from instant shell › does not include cookie values in instant shell during page load

expect(received).toContain(expected) // indexOf

Expected substring: "testCookie: hello"
Received string:    "testCookie: not set"

  411 |       const cookieValue = page.locator('[data-testid="cookie-value"]')
  412 |       await cookieValue.waitFor({ state: 'visible', timeout: 10000 })
> 413 |       expect(await cookieValue.textContent()).toContain('testCookie: hello')
      |                                               ^
  414 |     })
  415 |
  416 |     it('does not include dynamic param values in instant shell during page load', async () => {

  at Object.toContain (e2e/app-dir/instant-navigation-testing-api/instant-navigation-testing-api.test.ts:413:47)

pnpm test-dev test/e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts (job)

  • use-cache-search-params > should show an error when searchParams are used inside of a cached generateMetadata (DD)
  • use-cache-search-params > should show an error when searchParams are used inside of a cached generateViewport (DD)
  • use-cache-search-params > when searchParams are caught inside of "use cache" > should show an error (DD)
  • use-cache-search-params > when searchParams are caught inside of "use cache" > should also show an error after the second reload (DD)
  • use-cache-search-params > when searchParams are used inside of "use cache" > should show an error (DD)
Expand output

● use-cache-search-params › when searchParams are used inside of "use cache" › should show an error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params when searchParams are used inside of "use cache" should show an error 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-used used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-used": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-used/page.tsx (8:17) @ Page
  >  8 |   const param = (await searchParams).foo
       |                 ^",

  32 |
  33 |         if (isCacheComponentsEnabled) {
> 34 |           await expect(browser).toDisplayRedbox(`
     |                                 ^
  35 |            {
  36 |              "code": "E842",
  37 |              "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:34:33)

● use-cache-search-params › when searchParams are caught inside of "use cache" › should show an error

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params when searchParams are caught inside of "use cache" should show an error 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-caught used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-caught": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-caught/page.tsx (11:5) @ Page
  > 11 |     param = (await searchParams).foo
       |     ^",

  81 |
  82 |         if (isCacheComponentsEnabled) {
> 83 |           await expect(browser).toDisplayRedbox(`
     |                                 ^
  84 |            {
  85 |              "code": "E842",
  86 |              "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:83:33)

● use-cache-search-params › when searchParams are caught inside of "use cache" › should also show an error after the second reload

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params when searchParams are caught inside of "use cache" should also show an error after the second reload 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-caught used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-caught": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-caught/page.tsx (11:5) @ Page
  > 11 |     param = (await searchParams).foo
       |     ^",

  128 |
  129 |         if (isCacheComponentsEnabled) {
> 130 |           await expect(browser).toDisplayRedbox(`
      |                                 ^
  131 |            {
  132 |              "code": "E842",
  133 |              "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:130:33)

● use-cache-search-params › should show an error when searchParams are used inside of a cached generateMetadata

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params should show an error when searchParams are used inside of a cached generateMetadata 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-used-generate-metadata used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-used-generate-metadata": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-used-generate-metadata/page.tsx (9:17) @ generateMetadata
  >  9 |   const title = (await searchParams).title
       |                 ^",

  185 |
  186 |       if (isCacheComponentsEnabled) {
> 187 |         await expect(browser).toDisplayRedbox(`
      |                               ^
  188 |          {
  189 |            "code": "E842",
  190 |            "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:187:31)

● use-cache-search-params › should show an error when searchParams are used inside of a cached generateViewport

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `use-cache-search-params should show an error when searchParams are used inside of a cached generateViewport 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E842",
-   "description": "Route /search-params-used-generate-viewport used `searchParams` inside "use cache". Accessing dynamic request data inside a cache scope is not supported. If you need some search params inside a cached function await `searchParams` outside of the cached function and pass only the required search params as arguments to the cached function. See more info here: https://nextjs.org/docs/messages/next-request-in-use-cache",
+   "code": "E1290",
+   "description": "Route "/search-params-used-generate-viewport": `searchParams` can't be read inside `"use cache"`. Await it outside the cached function and pass what you need as an argument.
+ Learn more: https://nextjs.org/docs/messages/next-request-in-use-cache",
    "environmentLabel": "Prerender",
    "label": "Runtime Error",
    "source": "app/search-params-used-generate-viewport/page.tsx (9:17) @ generateViewport
  >  9 |   const color = (await searchParams).color
       |                 ^",

  224 |
  225 |       if (isCacheComponentsEnabled) {
> 226 |         await expect(browser).toDisplayRedbox(`
      |                               ^
  227 |          {
  228 |            "code": "E842",
  229 |            "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",

  at Object.toDisplayRedbox (e2e/app-dir/use-cache-search-params/use-cache-search-params.test.ts:226:31)

pnpm test-start test/production/app-dir/server-action-period-hash/server-action-period-hash-custom-key.test.ts (job)

  • app-dir - server-action-period-hash-custom-key > should have a different manifest if the encryption key from process env is changed (DD)
  • app-dir - server-action-period-hash-custom-key > should have the same manifest if the encryption key from process env is same (DD)
Expand output

● app-dir - server-action-period-hash-custom-key › should have a different manifest if the encryption key from process env is changed

can not run export while server is running, use next.stop() first

  253 |   ) {
  254 |     if (this.childProcess) {
> 255 |       throw new Error(
      |             ^
  256 |         `can not run export while server is running, use next.stop() first`
  257 |       )
  258 |     }

  at NextStartInstance.build (lib/next-modes/next-start.ts:255:13)
  at Object.build (production/app-dir/server-action-period-hash/server-action-period-hash-custom-key.test.ts:18:16)

● app-dir - server-action-period-hash-custom-key › should have the same manifest if the encryption key from process env is same

can not run export while server is running, use next.stop() first

  253 |   ) {
  254 |     if (this.childProcess) {
> 255 |       throw new Error(
      |             ^
  256 |         `can not run export while server is running, use next.stop() first`
  257 |       )
  258 |     }

  at NextStartInstance.build (lib/next-modes/next-start.ts:255:13)
  at Object.build (production/app-dir/server-action-period-hash/server-action-period-hash-custom-key.test.ts:32:16)

pnpm test-start test/production/app-dir/server-action-period-hash/server-action-period-hash.test.ts (job)

  • app-dir - server-action-period-hash > should have same manifest between continuous two builds (DD)
  • app-dir - server-action-period-hash > should have different manifest between two builds with period hash (DD)
Expand output

● app-dir - server-action-period-hash › should have same manifest between continuous two builds

can not run export while server is running, use next.stop() first

  253 |   ) {
  254 |     if (this.childProcess) {
> 255 |       throw new Error(
      |             ^
  256 |         `can not run export while server is running, use next.stop() first`
  257 |       )
  258 |     }

  at NextStartInstance.build (lib/next-modes/next-start.ts:255:13)
  at Object.build (production/app-dir/server-action-period-hash/server-action-period-hash.test.ts:17:16)

● app-dir - server-action-period-hash › should have different manifest between two builds with period hash

can not run export while server is running, use next.stop() first

  253 |   ) {
  254 |     if (this.childProcess) {
> 255 |       throw new Error(
      |             ^
  256 |         `can not run export while server is running, use next.stop() first`
  257 |       )
  258 |     }

  at NextStartInstance.build (lib/next-modes/next-start.ts:255:13)
  at Object.build (production/app-dir/server-action-period-hash/server-action-period-hash.test.ts:27:16)

pnpm test-dev-turbo test/e2e/app-dir/dynamic-data/dynamic-data.test.ts (turbopack) (job)

  • dynamic-data inside cache scope > displays redbox when accessing dynamic data inside a cache scope (DD)
Expand output

● dynamic-data inside cache scope › displays redbox when accessing dynamic data inside a cache scope

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `dynamic-data inside cache scope displays redbox when accessing dynamic data inside a cache scope 1`

- Snapshot  - 2
+ Received  + 3

@@ -1,8 +1,9 @@
  {
-   "code": "E846",
-   "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",
+   "code": "E1291",
+   "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) @ <anonymous>
  > 4 | const cookies = cache(() => nextCookies())
      |                                        ^",

  310 |       let browser = await next.browser('/cookies')
  311 |       try {
> 312 |         await expect(browser).toDisplayRedbox(`
      |                               ^
  313 |          {
  314 |            "code": "E846",
  315 |            "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",

  at Object.toDisplayRedbox (e2e/app-dir/dynamic-data/dynamic-data.test.ts:312:31)

Other failing CI jobs

Copy link
Copy Markdown
Contributor

@vercel vercel Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

use-cache.test.ts hard-codes the old "use cache" cookies error message, which no longer matches the rewritten source message and causes the test to fail.

Fix on Vercel

Comment thread packages/next/errors.json Outdated
@aurorascharff aurorascharff marked this pull request as ready for review June 1, 2026 11:57
Copilot AI review requested due to automatic review settings June 1, 2026 11:57
@aurorascharff aurorascharff requested a review from unstubbable June 1, 2026 12:03
Copy link
Copy Markdown
Contributor

@vercel vercel Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

dynamic-data.test.ts asserts the old unstable_cache() error messages and error codes (E846/E840/E838) that no longer match the source after the messages were centralized in use-cache-messages.ts

Fix on Vercel

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes and rewrites "use cache" / "use cache: private" misuse errors into a single message factory module, aiming to provide shorter, action-oriented diagnostics with consistent “Learn more” links across the server runtime and dev overlay.

Changes:

  • Added use-cache-messages.ts to centralize "use cache"-related error factories/strings and updated server call sites to use it.
  • Updated e2e expectations and regenerated packages/next/errors.json entries for the new/rewritten messages.
  • Tweaked dev overlay styling to improve spacing for chained Caused by: error blocks.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts Updates expected error codes/messages for "use cache" scenarios.
packages/next/src/server/web/spec-extension/revalidate.ts Switches to centralized revalidate-in-cache error factories.
packages/next/src/server/use-cache/use-cache-wrapper.ts Uses centralized "use cache" message exports for private/nested cache errors.
packages/next/src/server/use-cache/use-cache-messages.ts New module providing centralized "use cache" error factories, messages, and doc URLs.
packages/next/src/server/use-cache/cache-tag.ts Uses centralized error factory for cacheTag() outside "use cache".
packages/next/src/server/use-cache/cache-life.ts Uses centralized error factory for cacheLife() outside "use cache".
packages/next/src/server/route-modules/app-route/module.ts Uses centralized request-in-cache error factories for App Route handlers.
packages/next/src/server/request/utils.ts Uses centralized searchParams-in-cache error factory.
packages/next/src/server/request/headers.ts Uses centralized headers() misuse error factories for cache/unstable_cache.
packages/next/src/server/request/draft-mode.ts Uses centralized draft-mode mutation-in-cache error factories.
packages/next/src/server/request/cookies.ts Uses centralized cookies() misuse error factories for cache/unstable_cache.
packages/next/src/server/request/connection.ts Uses centralized connection() misuse error factories for cache/private/unstable_cache.
packages/next/src/next-devtools/dev-overlay/container/runtime-error/error-cause.tsx Adjusts .error-cause-message margin for better overlay spacing.
packages/next/errors.json Adds/updates error-code mappings for the new centralized messages.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/next/src/server/use-cache/use-cache-wrapper.ts
Copy link
Copy Markdown
Contributor

@vercel vercel Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

use-cache-search-params.test.ts asserts the old searchParams-in-use-cache error message and error code (E842), which no longer match the rewritten message produced by createSearchParamsInUseCacheError (E1289), causing the test to fail in CI.

Fix on Vercel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants