facebook/react · error · Error
407
407
Error message
Missing getServerSnapshot, which is required for server-rendered content. Will revert to client rendering.
What it means
When a component using useSyncExternalStore mounts, React reads a snapshot. If that mount render is hydrating server-rendered HTML (getIsHydrating() true) and no third getServerSnapshot argument was supplied, React cannot reproduce the value the server rendered from, so it throws instead of silently mismatching hydration.
Source
Thrown at packages/react-reconciler/src/ReactFiberHooks.js:1660
queue.lastRenderedState = newState;
}
return [newState, dispatch];
}
function mountSyncExternalStore<T>(
subscribe: (() => void) => () => void,
getSnapshot: () => T,
getServerSnapshot?: () => T,
): T {
const fiber = currentlyRenderingFiber;
const hook = mountWorkInProgressHook();
let nextSnapshot;
const isHydrating = getIsHydrating();
if (isHydrating) {
if (getServerSnapshot === undefined) {
throw new Error(
'Missing getServerSnapshot, which is required for ' +
'server-rendered content. Will revert to client rendering.',
);
}
nextSnapshot = getServerSnapshot();
if (__DEV__) {
if (!didWarnUncachedGetSnapshot) {
if (nextSnapshot !== getServerSnapshot()) {
console.error(
'The result of getServerSnapshot should be cached to avoid an infinite loop',
);
didWarnUncachedGetSnapshot = true;
}
}
}
} else {
nextSnapshot = getSnapshot();
if (__DEV__) {View on GitHub (pinned to eafeac097b)
Solutions
- Pass a third getServerSnapshot argument returning the stable server-side value, e.g. useSyncExternalStore(subscribe, () => window.innerWidth, () => 0)
- Cache the server snapshot (repeat calls must return the same value, or you get the separate uncached-getServerSnapshot warning)
- For truly client-only UI, gate rendering behind a mounted flag (useEffect sets state) so hydration never sees the store value
- If the store can report its initial value synchronously, reuse getSnapshot as getServerSnapshot only when it is safe to call on the server
Example fix
// before const scrollY = useSyncExternalStore( subscribeScroll, () => window.scrollY, // throws during hydration: no server snapshot ); // after const scrollY = useSyncExternalStore( subscribeScroll, () => window.scrollY, () => 0, // stable server-rendered value );
Defensive patterns
Strategy: validation
Validate before calling
// Wrapper that refuses the 2-argument form in any SSR-capable app
export function useSyncExternalStoreSSR<T>(
subscribe: () => () => void,
getSnapshot: () => T,
getServerSnapshot: () => T,
): T {
if (typeof getServerSnapshot !== 'function') {
throw new Error('getServerSnapshot is required when hydration is possible');
}
return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
} Type guard
// Type that makes the server snapshot non-optional at every call site type SSRStoreHook = <T>( subscribe: () => () => void, getSnapshot: () => T, getServerSnapshot: () => T, // required, not `?:` ) => T;
Prevention
- Always pass the third getServerSnapshot argument when a component can be server-rendered
- Return a cached/stable value from getServerSnapshot (constants or memoized) to also avoid the uncached-snapshot warning
- For browser-only values, render a constant on the server and update after mount via a mounted flag
- Ban the two-argument form in code review for SSR apps
When it happens
Trigger: useSyncExternalStore(subscribe, getSnapshot) called with only two arguments during hydration — i.e. the first client render over SSR HTML (Next.js, Remix, react-dom/hydrateRoot).
Common situations: Adding a browser-only store subscription (window size, matchMedia, localStorage, third-party stores) to a component that is server-rendered; hydration failures after introducing the hook in an SSR framework; libraries integrating external stores without a server snapshot.
Related errors
- Missing getServerSnapshot, which is required for server-rend
- An unsupported type was passed to use(): ${String(usable)}
- Unknown Fiber. Needs to be a function component to inspect h
- Can only set one of `children` or `props.dangerouslySetInner
- 558
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/d590ba7af02c1d1b.
Report an issue: GitHub.