You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Improve error handling for headers/cookies/draftMode in 'use cache' (#81716)
This ensures that we show a proper error with an error stack
(potentially source-mapped) when accessing
`headers`/`cookies`/`draftMode` in `'use cache'`, even when caught in
user-land code. For `searchParams` (currently triggering a timeout
error) we'll need a slightly different solution, which will be handled
in a future PR.
The approach chosen here is somewhat temporary, as we'd like to
implement compile-time errors instead for accessing any kind of request
data in `'use cache'` functions. However, this would require a larger
change to our bundlers.
closes NAR-201
Copy file name to clipboardExpand all lines: packages/next/src/server/request/cookies.ts
+4-1Lines changed: 4 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -81,9 +81,12 @@ export function cookies(): Promise<ReadonlyRequestCookies> {
81
81
if(workUnitStore){
82
82
switch(workUnitStore.type){
83
83
case'cache':
84
-
thrownewError(
84
+
consterror=newError(
85
85
`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`
86
86
)
87
+
Error.captureStackTrace(error,cookies)
88
+
workStore.invalidDynamicUsageError??=error
89
+
throwerror
87
90
case'unstable-cache':
88
91
thrownewError(
89
92
`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`
// We have a store we want to track dynamic data access to ensure we
294
295
// don't statically generate routes that manipulate draft mode.
295
296
if(workUnitStore?.phase==='after'){
296
297
thrownewError(
297
-
`Route ${store.route} used "${expression}" inside \`after\`. The enabled status of draftMode can be read inside \`after\` but you cannot enable or disable draftMode. See more info here: https://nextjs.org/docs/app/api-reference/functions/after`
298
+
`Route ${workStore.route} used "${expression}" inside \`after\`. The enabled status of draftMode can be read inside \`after\` but you cannot enable or disable draftMode. See more info here: https://nextjs.org/docs/app/api-reference/functions/after`
298
299
)
299
300
}
300
301
301
-
if(store.dynamicShouldError){
302
+
if(workStore.dynamicShouldError){
302
303
thrownewStaticGenBailoutError(
303
-
`Route ${store.route} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`
304
+
`Route ${workStore.route} with \`dynamic = "error"\` couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/app/building-your-application/rendering/static-and-dynamic#dynamic-rendering`
304
305
)
305
306
}
306
307
307
308
if(workUnitStore){
308
309
switch(workUnitStore.type){
309
-
case'cache':
310
-
thrownewError(
311
-
`Route ${store.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`
310
+
case'cache':{
311
+
consterror=newError(
312
+
`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`
312
313
)
314
+
Error.captureStackTrace(error,constructorOpt)
315
+
workStore.invalidDynamicUsageError??=error
316
+
throwerror
317
+
}
313
318
case'unstable-cache':
314
319
thrownewError(
315
-
`Route ${store.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`
320
+
`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`
316
321
)
317
-
case'prerender':
322
+
case'prerender':{
318
323
consterror=newError(
319
-
`Route ${store.route} used ${expression} without first calling \`await connection()\`. See more info here: https://nextjs.org/docs/messages/next-prerender-sync-headers`
324
+
`Route ${workStore.route} used ${expression} without first calling \`await connection()\`. See more info here: https://nextjs.org/docs/messages/next-prerender-sync-headers`
`${exportName} must not be used within a client component. Next.js should be preventing ${exportName} from being included in client components statically, but did not in this case.`
331
337
)
332
338
case'prerender-ppr':
333
339
returnpostponeWithTracking(
334
-
store.route,
340
+
workStore.route,
335
341
expression,
336
342
workUnitStore.dynamicTracking
337
343
)
338
344
case'prerender-legacy':
339
345
workUnitStore.revalidate=0
340
346
341
347
consterr=newDynamicServerError(
342
-
`Route ${store.route} couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`
348
+
`Route ${workStore.route} couldn't be rendered statically because it used \`${expression}\`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`
Copy file name to clipboardExpand all lines: packages/next/src/server/request/headers.ts
+4-1Lines changed: 4 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -79,9 +79,12 @@ export function headers(): Promise<ReadonlyHeaders> {
79
79
if(workUnitStore){
80
80
switch(workUnitStore.type){
81
81
case'cache':
82
-
thrownewError(
82
+
consterror=newError(
83
83
`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`
84
84
)
85
+
Error.captureStackTrace(error,headers)
86
+
workStore.invalidDynamicUsageError??=error
87
+
throwerror
85
88
case'unstable-cache':
86
89
thrownewError(
87
90
`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`
0 commit comments