facebook/react · error · Error

Server actions must be functions

Error message

Server actions must be functions

What it means

In the edge-build server writer for Parcel, loadServerAction resolves the action id against the server manifest, preloads its bundles, then requires the module and checks the binding is a function before invoking it. A missing export (stale name) or a non-function export fails the check and throws at request time.

Source

Thrown at packages/react-server-dom-parcel/src/server/ReactFlightDOMServerEdge.js:345

export function decodeAction<T>(body: FormData): Promise<() => T> | null {
  return decodeActionImpl(body, serverManifest);
}

export function decodeFormState<S>(
  actionResult: S,
  body: FormData,
): Promise<ReactFormState<S, ServerReferenceId> | null> {
  return decodeFormStateImpl(actionResult, body, serverManifest);
}

export function loadServerAction<F: (...any[]) => any>(id: string): Promise<F> {
  const reference = resolveServerReference<any>(serverManifest, id);
  return Promise.resolve(reference)
    .then(() => preloadModule(reference))
    .then(() => {
      const fn = requireModule(reference);
      if (typeof fn !== 'function') {
        throw new Error('Server actions must be functions');
      }
      return fn;
    });
}

View on GitHub (pinned to eafeac097b)

Solutions

  1. Ensure every export of a 'use server' file is an async function
  2. Rebuild manifest and bundles together after any export rename
  3. Assert in CI that every manifest-referenced export resolves to a function

Example fix

// before — non-function export reachable via the action id
'use server';
export const revalidate = 60; // stale manifest points 'content#revalidate' here

// after — actions are functions only; config lives elsewhere
'use server';
export async function revalidate() { /* ... */ }
Defensive patterns

Strategy: validation

Validate before calling

// dev/CI check: every export of a 'use server' module must be a function
import * as actions from './app-actions';
for (const [name, value] of Object.entries(actions)) {
  if (typeof value !== 'function') {
    throw new Error(`app-actions exports non-function '${name}'`);
  }
}

Type guard

export function isServerActionExport(mod, name) {
  const value = mod[name];
  return typeof value === 'function';
}

Try / catch

try {
  await loadServerAction(id);
} catch (e) {
  if (/Server actions must be functions/.test(e.message)) {
    // return a 500 and alert: manifest name does not resolve to a function export
    return new Response('Action unavailable', {status: 500});
  }
  throw e;
}

Prevention

When it happens

Trigger: A 'use server' module whose referenced export is missing or not a function: renamed export without a manifest rebuild, a const/object/class exported from the actions file, or a bundle that fails to expose the named binding.

Common situations: Refactors renaming exports while the edge manifest stays stale; mixing config constants into 'use server' files; divergent builds between manifest and action modules.

Related errors


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