Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
150 lines
4.2 KiB
Plaintext
150 lines
4.2 KiB
Plaintext
---
|
|
title: Cannot access `crypto.getRandomValue()`, `crypto.randomUUID()`, or another web or node crypto API that generates random values synchronously from a Client Component without a fallback UI defined
|
|
---
|
|
|
|
## Why This Error Occurred
|
|
|
|
A Client Component is accessing a random value synchronously from the Web Crypto API or from Node's `crypto` API.
|
|
|
|
Client Components primarily run in the browser however on an initial page visit, Next.js will serve an HTML page produced by simulating the client environment on the server. This process is called Server Side Rendering or SSR. Next.js will attempt to prerender this HTML ahead of time however if a Client Component accesses a random source during this prerender, it cannot include this component in the prerendered HTML, otherwise the value will be fixed on each user request and not random like expected. Next.js will use the nearest Suspense boundary around this component to prerender a fallback instead however in this instance there was no Suspense boundary.
|
|
|
|
There are a number of ways you might fix this issue depending on the specifics of your use case.
|
|
|
|
## Possible Ways to Fix It
|
|
|
|
### Provide Fallback UI
|
|
|
|
If your random value is intended to be unique per Request, add a Suspense boundary around the component that calls the crypto API that produces this value. This allows Next.js to prerender a fallback UI and fill in an actual random value when the user requests the page.
|
|
|
|
Before:
|
|
|
|
```jsx filename="app/blog/new/page.js"
|
|
'use client'
|
|
|
|
export default function Page() {
|
|
const newBlogId = crypto.randomUUID()
|
|
return <BlogAuthoringView id={newBlogId} />
|
|
}
|
|
```
|
|
|
|
After:
|
|
|
|
```jsx filename="app/blog/new/page.js"
|
|
"use client"
|
|
|
|
import { Suspense } from 'react'
|
|
|
|
export default function Page() {
|
|
return (
|
|
<Suspense fallback={<BlogAuthorSkeleton />}>
|
|
<DynamicAuthoringView />
|
|
</Suspense>
|
|
)
|
|
}
|
|
|
|
function BlogAuthorSkeleton() {
|
|
...
|
|
}
|
|
|
|
function DynamicAuthoringView() {
|
|
const newBlogId = crypto.randomUUID()
|
|
return <BlogAuthoringView id={newBlogId} />
|
|
}
|
|
```
|
|
|
|
### Only access crypto in the browser
|
|
|
|
If your random value is only intended for use in the browser you can move the call into an effect or event handler. React does not run effects during server rendering and there are no events during server rendering so neither option will require the prerender to exclude this component.
|
|
|
|
Before:
|
|
|
|
```jsx filename="app/workflow.js"
|
|
'use client'
|
|
|
|
function createSecureId() {
|
|
const array = new Uint8Array(16)
|
|
crypto.getRandomValues(array)
|
|
return array[0].toString(16)
|
|
}
|
|
|
|
export default function Workflow({ currentStep, onNext, onPrev }) {
|
|
const [id] = useState(createSecureId)
|
|
|
|
const next = onNext
|
|
? () => {
|
|
trackEvent(id, 'forward')
|
|
onNext()
|
|
}
|
|
: null
|
|
|
|
const previous = onPrev
|
|
? () => {
|
|
trackEvent(id, 'previous')
|
|
onPrev()
|
|
}
|
|
: null
|
|
|
|
return (
|
|
<>
|
|
{currentStep}
|
|
{next ? <button onClick={next}>Next</button> : null}
|
|
{previous ? <button onClick={previous}>Previous</button> : null}
|
|
</>
|
|
)
|
|
}
|
|
```
|
|
|
|
After:
|
|
|
|
```jsx filename="app/workflow.js"
|
|
'use client'
|
|
|
|
import { useRef } from 'react'
|
|
|
|
function createSecureId() {
|
|
const array = new Uint8Array(16)
|
|
crypto.getRandomValues(array)
|
|
return array[0].toString(16)
|
|
}
|
|
|
|
function getOrCreateId(ref) {
|
|
if (!ref.current) {
|
|
ref.current = createSecureId()
|
|
}
|
|
return ref.current
|
|
}
|
|
|
|
export default function Workflow({ currentStep, onNext, onPrev }) {
|
|
const idRef = useRef(null)
|
|
|
|
const next = onNext
|
|
? () => {
|
|
trackEvent(getOrCreateId(idRef), 'forward')
|
|
onNext()
|
|
}
|
|
: null
|
|
|
|
const previous = onPrev
|
|
? () => {
|
|
trackEvent(getOrCreateId(idRef), 'previous')
|
|
onPrev()
|
|
}
|
|
: null
|
|
|
|
return (
|
|
<>
|
|
{currentStep}
|
|
{next ? <button onClick={next}>Next</button> : null}
|
|
{previous ? <button onClick={previous}>Previous</button> : null}
|
|
</>
|
|
)
|
|
}
|
|
```
|
|
|
|
## 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)
|