withastro/astro · error · AstroError
ActionCalledFromServerError
ActionCalledFromServerError
Error message
Action called from a server-rendered page or endpoint without using `Astro.callAction()`. This wrapper must be used to call actions from server code.
What it means
Inside defineAction(), the wrapped safeServerHandler verifies its this binding is a genuine ActionAPIContext (carrying ACTION_API_CONTEXT_SYMBOL). If this is a plain function or lacks the symbol, AstroError ActionCalledFromServerError is thrown. This guards the handler from being invoked as a bare reference instead of through Astro.callAction().
Source
Thrown at packages/astro/src/actions/runtime/server.ts:57
: undefined,
>({
accept,
input: inputSchema,
handler,
}: {
input?: TInputSchema;
accept?: TAccept;
handler: ActionHandler<TInputSchema, TOutput>;
}): ActionClient<TOutput, TAccept, TInputSchema> & string {
const serverHandler =
accept === 'form'
? getFormServerHandler(handler, inputSchema)
: getJsonServerHandler(handler, inputSchema);
async function safeServerHandler(this: ActionAPIContext, unparsedInput: unknown) {
// The ActionAPIContext should always contain the `params` property
if (typeof this === 'function' || !isActionAPIContext(this)) {
throw new AstroError(ActionCalledFromServerError);
}
return callSafely(() => serverHandler(unparsedInput, this));
}
Object.assign(safeServerHandler, {
orThrow(this: ActionAPIContext, unparsedInput: unknown) {
if (typeof this === 'function') {
throw new AstroError(ActionCalledFromServerError);
}
return serverHandler(unparsedInput, this);
},
});
return safeServerHandler as ActionClient<TOutput, TAccept, TInputSchema> & string;
}
function getFormServerHandler<TOutput, TInputSchema extends z.$ZodType>(
handler: ActionHandler<TInputSchema, TOutput>,View on GitHub (pinned to d081033d5f)
Solutions
- Always call via Astro.callAction(actions.myAction, input) on the server.
- Do not invoke the action reference directly; do not pass it as a detached callback.
- If you need the logic elsewhere, extract a plain function and call that from both the handler and the other site.
Example fix
// before
import { actions } from './actions';
const { myAction } = actions;
const result = await myAction(input);
// after
const result = await Astro.callAction(actions.myAction, input); Defensive patterns
Strategy: validation
Validate before calling
// Disallow calling action references directly; route all server calls through Astro.callAction.
// Static lint rule (conceptual): flag any `await someAction(` that is not preceded by Astro.callAction.
// Example runtime helper used in server code:
async function serverCall<T>(astro: any, fn: Function, input: unknown): Promise<T> {
if (typeof astro?.callAction !== 'function') throw new Error('Use Astro.callAction on the server');
return astro.callAction(fn, input);
} Prevention
- Never destructure and call actions on the server; use Astro.callAction().
- Do not pass action references as detached callbacks.
- Extract reusable logic into plain functions called by both handler and other code.
When it happens
Trigger: Destructuring an action and calling it directly (await myAction(input)) on the server, or passing the action reference as a callback and then invoking it, so this is undefined/not the Astro context.
Common situations: Server code that treats the action like an ordinary async function; passing actions.foo into a utility that calls it; calling from a non-Astro module where no context is bound.
Related errors
- ActionCalledFromServerError
- Expected `server` export in actions file to be an object. Re
- [astro:actions] `defineAction()` unexpectedly used on the cl
- [astro:actions] `getActionContext()` unexpectedly used on th
- BAD_REQUEST
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/157518ab28c2351d.
Report an issue: GitHub.