Files
vercel__next.js/errors/next-prerender-sync-headers.mdx
Wyatt Johnson 8abbb3dc2e refactor: rename experimental.dynamicIO to experimental.cacheComponents (#81562)
## What?

Rename `experimental.dynamicIO` to `experimental.cacheComponents` across
the Next.js codebase.

## Why?

We're going to be merging the functionality of the `ppr`, `dynamicIO`
and `useCache` experimental flags into the singular `cacheComponents`
flag to reduce complexity of the codebase and simplify adoption for
users wanting to experiment with experimental features.

## How?

- Renamed the configuration option from `experimental.dynamicIO` to
`experimental.cacheComponents`
- Added deprecation handling with automatic migration for the old option
name
- Updated all documentation, tests, and internal references
- Updated Rust code in SWC transforms and Turbopack
- Maintained backward compatibility with deprecation warnings

NAR-158
2025-07-17 19:30:28 -06:00

98 lines
3.7 KiB
Plaintext

---
title: Cannot access Request information synchronously with `cookies()`, `headers()`, or `draftMode()`
---
## Why This Error Occurred
In Next.js 15 global functions that provide access to Request Header information such as `cookies()`, `headers()`, and `draftMode()` are each now `async` and return a `Promise` rather than the associated object directly.
To support migrating to the async APIs Next.js 15 still supports accessing properties of the underlying object directly on the returned Promise. However when `cacheComponents` is enabled it is an error to do so.
## Possible Ways to Fix It
If you haven't already followed the Next.js 15 upgrade guide which includes running a codemod to auto-convert to the necessary async form of these APIs start there.
[Next 15 Upgrade Guide](/docs/app/guides/upgrading/version-15#async-request-apis-breaking-change)
If you have already run the codemod on your project look for instances of the string `@next-codemod-error` to see where the codemod was unable to convert to the async form. You will have to refactor your code manually here to make it compatible with the new result type.
Before:
```jsx filename=".../token-utils.js"
// This function is sync and the codemod won't make it async
// because it doesn't know about every callsite that uses it.
export function getToken() {
// @next-codemod-error ...
return cookies().get('token')
}
```
```jsx filename="app/page.js"
import { getToken } from '.../token-utils'
export default function Page() {
const token = getToken();
validateToken(token)
return ...
}
```
After:
```jsx filename=".../token-utils.js"
export async function Page() {
return (await cookies()).get(token)
}
```
```jsx filename="app/page.js"
import { getToken } from '.../token-utils'
export default async function Page() {
const token = await getToken();
validateToken(token)
return ...
}
```
If you do not find instances of this string then it is possible the synchronous use of Request Header data is inside a 3rd party library. You should identify which library is using this function and see if it has published a Next 15 compatible version that adheres to the new Promise return type.
As a last resort you can add `await connection()` before calling the 3rd party function which uses this API. This will inform Next.js that everything after this await should be excluded from prerendering. This will continue to work until we remove support for synchronously access Request data which is expected to happen in the next major version.
Before:
```jsx filename="app/page.js"
import { getDataFrom3rdParty } from '3rdparty'
export default function Page() {
// Imagine this function access Request data synchronously
// on the inside even if it has an async external interface
const token = await getDataFrom3rdParty();
return ...
}
```
After:
```jsx filename="app/page.js"
import { connection } from 'next/server'
export default async function Page() {
await connection()
// Everything from here down will be excluded from prerendering
const token = await getDataFrom3rdParty();
validateToken(token)
return ...
}
```
Note that with `await connection()` and `cacheComponents` it is still required that there is a Suspense boundary somewhere above the component that uses `await connection()`. If you do not have any Suspense boundary parent you will need to add one where is appropriate to describe a fallback UI.
## Useful Links
- [`headers` function](/docs/app/api-reference/functions/headers)
- [`cookies` function](/docs/app/api-reference/functions/cookies)
- [`draftMode` function](/docs/app/api-reference/functions/draft-mode)
- [`connection` function](/docs/app/api-reference/functions/connection)
- [`Suspense` React API](https://react.dev/reference/react/Suspense)