facebook/react · error · Error
Client Functions cannot be passed directly to Server Functio
Error message
Client Functions cannot be passed directly to Server Functions. Only Functions passed from the Server can be passed back again.
What it means
In the Flight reply protocol, functions can travel client-to-server only as server references - functions defined with 'use server', which carry an $$id the server can bind back to an implementation. A plain client-side function has no server identity, so when serializeReply meets one (after the temporary-reference dedupe check fails) it throws with this explanation. The rule keeps the network boundary explicit: code defined on the client never executes on the server.
Source
Thrown at packages/react-client/src/ReactFlightReplyClient.js:847
formData.set(formFieldPrefix + refId, referenceClosureJSON);
const serverReferenceId = serializeServerReferenceID(refId);
// Store the server reference ID for deduplication.
writtenObjects.set(value, serverReferenceId);
return serverReferenceId;
}
if (temporaryReferences !== undefined && key.indexOf(':') === -1) {
// TODO: If the property name contains a colon, we don't dedupe. Escape instead.
const parentReference = writtenObjects.get(parent);
if (parentReference !== undefined) {
// If the parent has a reference, we can refer to this object indirectly
// through the property name inside that parent.
const reference = parentReference + ':' + key;
// Store this object so that the server can refer to it later in responses.
writeTemporaryReference(temporaryReferences, reference, value);
return serializeTemporaryReferenceMarker();
}
}
throw new Error(
'Client Functions cannot be passed directly to Server Functions. ' +
'Only Functions passed from the Server can be passed back again.',
);
}
if (typeof value === 'symbol') {
if (temporaryReferences !== undefined && key.indexOf(':') === -1) {
// TODO: If the property name contains a colon, we don't dedupe. Escape instead.
const parentReference = writtenObjects.get(parent);
if (parentReference !== undefined) {
// If the parent has a reference, we can refer to this object indirectly
// through the property name inside that parent.
const reference = parentReference + ':' + key;
// Store this object so that the server can refer to it later in responses.
writeTemporaryReference(temporaryReferences, reference, value);
return serializeTemporaryReferenceMarker();
}
}View on GitHub (pinned to eafeac097b)
Solutions
- Make the function a Server Function: add 'use server' at the top of its module or above the definition, then pass that reference instead of a closure
- Replace the callback with data: send a discriminator/ID plus args and have the server switch on it
- Expose several named server functions and choose which one to call on the client
- Audit nested option objects before sending them - strip or replace any function-valued properties
Example fix
// before
await applyOp(values, x => x * 2); // client closure -> throws
// after
// ops.ts
'use server';
export async function double(x) { return x * 2; }
// client
import {double} from './ops';
await applyOp(values, double); // server reference, OK Defensive patterns
Strategy: type-guard
Validate before calling
// Scan the argument tree for functions that are not server references
import {isServerReference} from './guards'; // typeGuard below
function assertNoClientFunctions(v: unknown, seen = new Set()): void {
if (v === null || typeof v !== 'object' && typeof v !== 'function') return;
seen.add(v);
if (typeof v === 'function' && !isServerReference(v)) {
throw new Error('Client function cannot be passed to a Server Function');
}
if (typeof v === 'object') {
Object.values(v).forEach(c => { if (!seen.has(c)) assertNoClientFunctions(c, seen); });
}
} Type guard
const SERVER_REFERENCE = Symbol.for('react.server.reference');
const isServerReference = (
fn: unknown,
): fn is ((...args: any[]) => Promise<any>) & {$$id: string} =>
typeof fn === 'function' &&
(fn as any).$$typeof === SERVER_REFERENCE &&
typeof (fn as any).$$id === 'string'; Prevention
- Never pass client closures across the boundary - define remote logic with 'use server' and pass that reference
- Replace callback parameters with command/ID patterns
- Strip or map function-valued properties before sending option objects
- Grep call sites for server functions invoked with inline arrows during review
When it happens
Trigger: Passing an arrow function, closure, class method, or callback as a Server Function argument: await runOp(values, x => x * 2); also functions nested inside objects/arrays in the args tree, or a function received in props forwarded to a server action.
Common situations: Attempted callback-style APIs across the network; refactoring local functions into actions and forgetting a call site still passes a client closure; libraries whose option objects accept callbacks being sent wholesale to server functions.
Related errors
- Missing a temporary reference set but the RSC response retur
- React Element cannot be passed to Server Functions from the
- Only plain objects, and a few built-ins, can be passed to Se
- Symbols cannot be passed to a Server Function without a temp
- Type ${typeof value} is not supported as an argument to a Se
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/da5409b39b679a37.
Report an issue: GitHub.