Files
vercel__next.js/errors/next-prerender-crypto.mdx
Josh Story ed5d085fb1 [Cache Components] Error for Sync IO in Server Components during Static Prerender (#82500)
Currently we error if you cannot produce a shell unless you have a
Suspense boundary above the root. This is fine for normal IO but sync IO
like Math.random() and new Date() have much more significant bad
consequences for prerendering. Instead of treating these errors as
another flavor of "must have a shell" validation we should instead treat
them like they must be guarded behind something else dynamic like `await
connection()`.

In addition to unconditionally erroring for Sync IO in Server Components
when prerendering this change also removes the Sync IO warning for
runtime prefetches. This is because at the moment there is no way to
debug these errors in dev. In the future we will add validation for
prefetches and need to add back in some ability to warn for these cases
but until then we will leave this case as a silent deopt.
2025-08-20 15:23:31 +00:00

108 lines
3.8 KiB
Plaintext

---
title: Cannot access `crypto.getRandomValue()`, `crypto.randomUUID()`, or another web or node crypto API that generates random values synchronously before other uncached data or Request data in a Server Component
---
## Why This Error Occurred
An API that produces a random value synchronously from the Web Crypto API or from Node's `crypto` package was used in a Server Component before accessing other uncached data through APIs like `fetch()` and native database drivers, or Request data through Next.js APIs like `cookies()`, `headers()`, `connection()` and `searchParams`. Accessing random values synchronously in this way interferes with the prerendering and prefetching capabilities of Next.js.
## Possible Ways to Fix It
If the random crypto value is appropriate to be prerendered and prefetched consider moving it into a Cache Component or Cache Function with the `"use cache"` directive.
If the random crypto value is intended to be generated on every user request consider whether an async API exists that achieves the same result. If not consider whether you can move the random crypto value generation later, behind other existing uncached data or Request data access. If there is no way to do this you can always precede the random crypto value generation with Request data access by using `await connection()`.
### Cache the token value
If you are generating a token to talk to a database that itself should be cached move the token generation inside the `"use cache"`.
Before:
```jsx filename="app/page.js"
async function getCachedData(token: string) {
"use cache"
return db.query(token, ...)
}
export default async function Page() {
const token = crypto.getRandomUUID()
const data = await getCachedData(token);
return ...
}
```
After:
```jsx filename="app/page.js"
async function getCachedData() {
"use cache"
const token = crypto.getRandomUUID()
return db.query(token, ...)
}
export default async function Page() {
const data = await getCachedData();
return ...
}
```
### Use an async API at request-time
If you require this random value to be unique per Request and an async version of the API exists switch to it instead. Also ensure that there is a parent Suspense boundary that defines a fallback UI Next.js can use while rendering this component on each Request.
Before:
```jsx filename="app/page.js"
import { generateKeySync } from 'node:crypto'
export default async function Page() {
const key = generateKeySync('hmac', { ... })
const digestedData = await digestDataWithKey(data, key);
return ...
}
```
After:
```jsx filename="app/page.js"
import { generateKey } from 'node:crypto'
export default async function Page() {
const key = await new Promise(resolve => generateKey('hmac', { ... }, key => resolve(key)))
const digestedData = await digestDataWithKey(data, key);
return ...
}
```
### Use `await connection()` at request-time
If you require this random value to be unique per Request and an async version of the API does not exist, call `await connection()`. Also ensure that there is a parent Suspense boundary that defines a fallback UI Next.js can use while rendering this component on each Request.
Before:
```jsx filename="app/page.js"
export default async function Page() {
const uuid = crypto.randomUUID()
return <RequestId id={uuid} />
}
```
After:
```jsx filename="app/page.js"
import { connection } from 'next/server'
export default async function Page() {
await connection()
const uuid = crypto.randomUUID()
return <RequestId id={uuid} />
}
```
## Useful Links
- [`connection` function](/docs/app/api-reference/functions/connection)
- [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API)
- [Node Crypto API](https://nodejs.org/docs/latest/api/crypto.html)
- [`Suspense` React API](https://react.dev/reference/react/Suspense)