{"record":{"id":"da5409b39b679a37","repo":"facebook/react","slug":"client-functions-cannot-be-passed-directly-to-serv","errorCode":null,"errorMessage":"Client Functions cannot be passed directly to Server Functions. Only Functions passed from the Server can be passed back again.","messagePattern":"Client Functions cannot be passed directly to Server Functions\\. Only Functions passed from the Server can be passed back again\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-client/src/ReactFlightReplyClient.js","lineNumber":847,"sourceCode":"        formData.set(formFieldPrefix + refId, referenceClosureJSON);\n        const serverReferenceId = serializeServerReferenceID(refId);\n        // Store the server reference ID for deduplication.\n        writtenObjects.set(value, serverReferenceId);\n        return serverReferenceId;\n      }\n      if (temporaryReferences !== undefined && key.indexOf(':') === -1) {\n        // TODO: If the property name contains a colon, we don't dedupe. Escape instead.\n        const parentReference = writtenObjects.get(parent);\n        if (parentReference !== undefined) {\n          // If the parent has a reference, we can refer to this object indirectly\n          // through the property name inside that parent.\n          const reference = parentReference + ':' + key;\n          // Store this object so that the server can refer to it later in responses.\n          writeTemporaryReference(temporaryReferences, reference, value);\n          return serializeTemporaryReferenceMarker();\n        }\n      }\n      throw new Error(\n        'Client Functions cannot be passed directly to Server Functions. ' +\n          'Only Functions passed from the Server can be passed back again.',\n      );\n    }\n\n    if (typeof value === 'symbol') {\n      if (temporaryReferences !== undefined && key.indexOf(':') === -1) {\n        // TODO: If the property name contains a colon, we don't dedupe. Escape instead.\n        const parentReference = writtenObjects.get(parent);\n        if (parentReference !== undefined) {\n          // If the parent has a reference, we can refer to this object indirectly\n          // through the property name inside that parent.\n          const reference = parentReference + ':' + key;\n          // Store this object so that the server can refer to it later in responses.\n          writeTemporaryReference(temporaryReferences, reference, value);\n          return serializeTemporaryReferenceMarker();\n        }\n      }","sourceCodeStart":829,"sourceCodeEnd":865,"githubUrl":"https://github.com/facebook/react/blob/eafeac097ba51e1eab809c07102126bd5f8e5425/packages/react-client/src/ReactFlightReplyClient.js#L829-L865","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait applyOp(values, x => x * 2); // client closure -> throws\n\n// after\n// ops.ts\n'use server';\nexport async function double(x) { return x * 2; }\n// client\nimport {double} from './ops';\nawait applyOp(values, double); // server reference, OK","handlingStrategy":"type-guard","validationCode":"// Scan the argument tree for functions that are not server references\nimport {isServerReference} from './guards'; // typeGuard below\nfunction assertNoClientFunctions(v: unknown, seen = new Set()): void {\n  if (v === null || typeof v !== 'object' && typeof v !== 'function') return;\n  seen.add(v);\n  if (typeof v === 'function' && !isServerReference(v)) {\n    throw new Error('Client function cannot be passed to a Server Function');\n  }\n  if (typeof v === 'object') {\n    Object.values(v).forEach(c => { if (!seen.has(c)) assertNoClientFunctions(c, seen); });\n  }\n}","typeGuard":"const SERVER_REFERENCE = Symbol.for('react.server.reference');\nconst isServerReference = (\n  fn: unknown,\n): fn is ((...args: any[]) => Promise<any>) & {$$id: string} =>\n  typeof fn === 'function' &&\n  (fn as any).$$typeof === SERVER_REFERENCE &&\n  typeof (fn as any).$$id === 'string';","tryCatchPattern":null,"preventionTips":["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"],"tags":["server-functions","serialization","use-server","rsc","callbacks"],"backgroundTag":"non-serializable-argument","analyzedSha":"eafeac097ba51e1eab809c07102126bd5f8e5425","analyzedAt":"2026-08-21T22:01:08.818Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}