facebook/react · error · Error
379
379
Error message
Refs cannot be used in Server Components, nor passed to Client Components.
What it means
While serializing RSC output, React found a non-null ref on an element rendered by a Server Component or passed toward a Client Component. Refs are live, mutable handles bound to client-side instances, so there is no wire format for them across the RSC boundary. React hard-throws instead of silently dropping the ref, because silent loss would corrupt any code that relies on it.
Source
Thrown at packages/react-server/src/ReactFlightServer.js:2337
}
}
function renderElement(
request: Request,
task: Task,
type: any,
key: ReactKey,
ref: mixed,
props: any,
validated: number, // DEV only
): ReactJSONValue {
if (ref !== null && ref !== undefined) {
// When the ref moves to the regular props object this will implicitly
// throw for functions. We could probably relax it to a DEV warning for other
// cases.
// TODO: `ref` is now just a prop when `enableRefAsProp` is on. Should we
// do what the above comment says?
throw new Error(
'Refs cannot be used in Server Components, nor passed to Client Components.',
);
}
if (__DEV__) {
jsxPropsParents.set(props, type);
if (typeof props.children === 'object' && props.children !== null) {
jsxChildrenParents.set(props.children, type);
}
}
if (
typeof type === 'function' &&
!isClientReference(type) &&
!isOpaqueTemporaryReference(type)
) {
// This is a Server Component.
return renderFunctionComponent(request, task, key, type, props, validated);
} else if (type === REACT_FRAGMENT_TYPE && key === null) {
// For key-less fragments, we add a small optimization to avoid serializingView on GitHub (pinned to eafeac097b)
Solutions
- Move the ref-consuming logic into a file marked 'use client' and reference that component instead.
- Restructure so the server passes plain data and the client component owns its own refs.
- If a handle must cross, pass an id/string prop and let the client resolve the node itself.
Example fix
// before — Server Component
<ClientInput ref={inputRef} defaultValue="hi" />
// after — the ref lives in the client file
// Input.client.tsx
'use client';
export function ClientInput(props) {
const ref = useRef(null);
return <input ref={ref} {...props} />;
}
// Server Component
<ClientInput defaultValue="hi" /> Defensive patterns
Strategy: type-guard
Validate before calling
// DEV-time walk: catch ref-carrying elements before render does.
const hasRef = (el: any) =>
el != null && typeof el === 'object' && typeof el.$$typeof === 'symbol' && el.ref != null;
export function assertNoRefs(props: Record<string, unknown>) {
for (const [k, v] of Object.entries(props)) {
if (hasRef(v)) throw new Error(`prop ${k} is an element carrying a ref — move ref usage to a client component`);
}
} Type guard
export function elementHasRef(el: unknown): boolean {
return typeof el === 'object' && el !== null && 'ref' in el && (el as any).ref != null;
} Prevention
- Mark ref-using components 'use client' at the file level.
- Never accept a ref prop in components shared between server and client trees.
- Lint for useRef/forwardRef usage in files without 'use client'.
When it happens
Trigger: Rendering <SomeComponent ref={r}/> inside a Server Component tree; passing an element that carries ref as a prop value into a Client Component; libraries injecting refs via cloneElement in server-rendered layout code.
Common situations: Trying to use useRef in a shared component that ends up in the server graph; forwarding refs through a component not marked 'use client'; design-system components imported into a server tree.
Related errors
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/194b740925ee8ce5.
Report an issue: GitHub.