facebook/react · error · Error

374

374

Error message

Event handlers cannot be passed to Client Component props.%s
If you need interactivity, consider converting part of this to a Client Component.

What it means

A function value reached a prop whose name matches /^on[A-Z]/ — React's convention for event handlers. Functions cannot be serialized from Server Components to Client Components, and event handlers specifically must run in the browser, so this case gets a dedicated message that also points at the fix (convert the interactive part to a Client Component).

Source

Thrown at packages/react-server/src/ReactFlightServer.js:4267

        return serializeTemporaryReference(request, tempRef);
      }
    }

    if (enableTaint) {
      const tainted = TaintRegistryObjects.get(value);
      if (tainted !== undefined) {
        throwTaintViolation(tainted);
      }
    }

    if (isOpaqueTemporaryReference(value)) {
      throw new Error(
        'Could not reference an opaque temporary reference. ' +
          'This is likely due to misconfiguring the temporaryReferences options ' +
          'on the server.',
      );
    } else if (/^on[A-Z]/.test(parentPropertyName)) {
      throw new Error(
        'Event handlers cannot be passed to Client Component props.' +
          describeObjectForErrorMessage(parent, parentPropertyName) +
          '\nIf you need interactivity, consider converting part of this to a Client Component.',
      );
    } else if (
      __DEV__ &&
      (jsxChildrenParents.has(parent) ||
        (jsxPropsParents.has(parent) && parentPropertyName === 'children'))
    ) {
      const componentName = value.displayName || value.name || 'Component';
      throw new Error(
        'Functions are not valid as a child of Client Components. This may happen if ' +
          'you return ' +
          componentName +
          ' instead of <' +
          componentName +
          ' /> from render. ' +
          'Or maybe you meant to call this function rather than return it.' +

View on GitHub (pinned to eafeac097b)

Solutions

  1. Move the interactive piece into a 'use client' component that owns its own handler.
  2. Expose the behavior as a Server Action: mark the function 'use server' and pass that reference instead.
  3. Restructure props to data only (an action id or preset key the client component maps to a local handler).

Example fix

// before — Server Component
<SaveButton onClick={() => save(row.id)}>Save</SaveButton>

// after — the behavior is a server action
// actions.ts
'use server';
export async function save(id: string) { /* ... */ }

// SaveButton.tsx
'use client';
export function SaveButton({id}) {
  return <button formAction={save.bind(null, id)}>Save</button>;
}
Defensive patterns

Strategy: type-guard

Validate before calling

export function findFunctionProps(props: Record<string, unknown>): string[] {
  return Object.entries(props)
    .filter(([, v]) => typeof v === 'function')
    .map(([k]) => k);
}
// DEV guard before returning JSX from a server component:
const bad = findFunctionProps(props);
if (bad.length) throw new Error('non-serializable props: ' + bad.join(', '));

Type guard

export function isEventHandlerProp(name: string, value: unknown): boolean {
  return /^on[A-Z]/.test(name) && typeof value === 'function';
}

Prevention

When it happens

Trigger: <ClientButton onClick={() => save(id)} /> rendered from a Server Component; passing onChange/onSubmit handlers down through a props object; cloneElement injecting onXxx props inside server-rendered layout code.

Common situations: Converting an existing client page to RSC and letting a handler closure cross the boundary; shared UI kits whose handler props are used from server trees; copy-pasted interactive snippets into server files.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/93fc0e86b30add8f. Report an issue: GitHub.