errors/next-prerender-runtime-crypto.mdx
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 the connection() API. While typically random crypto values can be guarded behind Runtime data like cookies(), headers(), params, and searchParams, this particular route is configured for Runtime Prefetching which makes these APIs available as part of the prefetch request. Accessing random values synchronously without preceding it with uncached data or await connection() interferes with the framework's ability to produce a correct prefetch result.
If the random crypto value is appropriate to be 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 navigation 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().
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:
export const unstable_instant = {
prefetch: 'runtime',
samples: [...],
}
async function getCachedData(token: string, userId: string) {
"use cache"
return db.query(token, userId, ...)
}
export default async function Page({ params }) {
const { userId } = await params
const token = crypto.randomUUID()
const data = await getCachedData(token, userId);
return ...
}
After:
export const unstable_instant = {
prefetch: 'runtime',
samples: [...],
}
async function getCachedData(userId: string) {
"use cache"
const token = crypto.randomUUID()
return db.query(token, userId, ...)
}
export default async function Page({ params }) {
const { userId } = await params
const data = await getCachedData(userId);
return ...
}
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:
export const unstable_instant = {
prefetch: 'runtime',
samples: [...],
}
import { generateKeySync } from 'node:crypto'
export default async function Page({ params }) {
const { dataId } = await params
const data = await fetchData(dataId)
const key = generateKeySync('hmac', { ... })
const digestedData = await digestDataWithKey(data, key);
return ...
}
After:
export const unstable_instant = {
prefetch: 'runtime',
samples: [...],
}
import { generateKey } from 'node:crypto'
export default async function Page({ params }) {
const { dataId } = await params
const data = await fetchData(dataId)
const key = await new Promise(resolve => generateKey('hmac', { ... }, key => resolve(key)))
const digestedData = await digestDataWithKey(data, key);
return ...
}
await connection() at request-timeIf 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:
export const unstable_instant = {
prefetch: 'runtime',
samples: [...],
}
export default async function Page({ params }) {
const { sessionId } = await params
const uuid = crypto.randomUUID()
return <RequestId sessionId={sessionId} id={uuid} />
}
After:
export const unstable_instant = {
prefetch: 'runtime',
samples: [...],
}
import { connection } from 'next/server'
export default async function Page({ params }) {
await connection()
const { sessionId } = await params
const uuid = crypto.randomUUID()
return <RequestId sessionId={sessionId} id={uuid} />
}