facebook/react · error · Error
Server actions must be functions
Error message
Server actions must be functions
What it means
In the browser-build server writer for Parcel, an incoming action request goes through loadServerAction: resolve the id against the server manifest, preload the referenced bundles, then require the module and use the resolved binding as the action. The binding must be a function; a missing export name (undefined after a rename) or a non-function export (const, object, class) fails the typeof check and throws.
Source
Thrown at packages/react-server-dom-parcel/src/server/ReactFlightDOMServerBrowser.js:295
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
- Make every export of a 'use server' file an async function
- Rebuild the manifest/bundles after renaming exports so ids and export names match
- Add a unit test that imports each 'use server' module and asserts typeof export === 'function' for every name the manifest references
Example fix
// before — manifest says 'saveNote' but the module exports something else
'use server';
export async function persistNote(note) { /* renamed */ }
export const noteSchema = {type: 'object'}; // non-function export gets referenced by stale id
// after — only async function exports, manifest rebuilt
'use server';
export async function saveNote(note) { /* ... */ } 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 './note-actions';
for (const [name, value] of Object.entries(actions)) {
if (typeof value !== 'function') {
throw new Error(`note-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)) {
// stale manifest or non-function export — rebuild and verify the named export exists
return new Response('Action unavailable', {status: 500});
}
throw e;
} Prevention
- Keep 'use server' files limited to async function exports
- Rebuild manifests whenever action exports are renamed
- Assert typeof export === 'function' for every manifest-referenced name in CI
When it happens
Trigger: A 'use server' module whose referenced export is not a function, or whose export name no longer exists because the manifest is stale after a rename — requireModule resolves the module but the named binding is undefined.
Common situations: Renaming an exported action without rebuilding the manifest; exporting constants or objects alongside actions in a 'use server' file; default-vs-named export confusion between builds.
Related errors
- Server actions must be functions
- Invalid server action: ${ref}
- No server callback has been registered. Call setServerCallba
- Attempted to load a Server Reference outside the hosted root
- Server Functions cannot be called during initial render. Thi
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/179eb76582d7649b.
Report an issue: GitHub.