"Missing getServerSnapshot" means useSyncExternalStore has no server
snapshot function. React needs that third argument for server rendering and
hydration. Add a function that returns the same initial value on the server
and in the browser.
The error
React 18 and 19, in development:
Missing getServerSnapshot, which is required for server-rendered content. Will revert to client rendering.In production it is error #407:
Minified React error #407; visit https://react.dev/errors/407 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.What missing getServerSnapshot means
useSyncExternalStore reads a value outside React. The snapshot functions
serve different stages:
| When | React calls |
|---|---|
| Server rendering | getServerSnapshot |
| Hydration, in the browser | getServerSnapshot again, and expects the server's value |
| After hydration | getSnapshot, and re-renders if the value changed |
Without getServerSnapshot, React cannot safely render the store's value on
the server. It may fall back to client rendering at the nearest Suspense
boundary or fail the server render if there is no suitable boundary.
Common causes
- A hook written for client-only React, then used in a server-rendered app.
- A copied example that shows only two arguments.
- A store library whose hook calls
useSyncExternalStorewithout a server snapshot, in an older version or a custom wrapper.
How to fix it
-
Find the hook in the component stack.
-
Add a server snapshot for the value shown before the browser store is available. Before:
hooks/use-online.ts import { useSyncExternalStore } from "react"; function subscribe(callback: () => void) { window.addEventListener("online", callback); window.addEventListener("offline", callback); return () => { window.removeEventListener("online", callback); window.removeEventListener("offline", callback); }; } export function useOnline() { return useSyncExternalStore(subscribe, () => navigator.onLine); }After:
hooks/use-online.ts import { useSyncExternalStore } from "react"; function subscribe(callback: () => void) { window.addEventListener("online", callback); window.addEventListener("offline", callback); return () => { window.removeEventListener("online", callback); window.removeEventListener("offline", callback); }; } export function useOnline() { return useSyncExternalStore( subscribe, () => navigator.onLine, () => true ); } -
Keep the server snapshot stable. It also runs in the browser during hydration. Do not read
localStoragethere or branch ontypeof window. Return a constant or a value passed from the server.
For a saved preference, a server-readable cookie may provide the initial value. See storage.
Find every instance
require-stable-server-snapshot
flags a missing or unstable server snapshot:
npm install -D eslint-plugin-hydration-proofAt runtime, hydration-proof can report a server boundary failure as HP2006, or a fallback during hydration as HP2003 or HP2004:
npx hydration-proof test