withastro/astro · error · Error
[astro:actions] `getActionContext()` unexpectedly used on th
Error message
[astro:actions] `getActionContext()` unexpectedly used on the client.
What it means
The client stub for getActionContext() throws on any invocation in the browser. getActionContext() is a server-only API used inside action handlers to read the request context; like defineAction() it must never execute client-side. Hitting it means server action runtime code was imported into the client.
Source
Thrown at packages/astro/src/actions/runtime/entrypoints/client.ts:32
ActionError,
isActionError,
isInputError,
} from '../client.js';
export type {
ActionAPIContext,
ActionClient,
ActionErrorCode,
ActionInputSchema,
ActionReturnType,
SafeResult,
} from '../types.js';
export function defineAction() {
throw new Error('[astro:actions] `defineAction()` unexpectedly used on the client.');
}
export function getActionContext() {
throw new Error('[astro:actions] `getActionContext()` unexpectedly used on the client.');
}
export const getActionPath = createGetActionPath({
baseUrl: import.meta.env.BASE_URL,
shouldAppendTrailingSlash,
});
export const actions = createActionsProxy({
handleAction: async (param, path) => {
const headers = new Headers();
headers.set('Accept', 'application/json');
// Apply adapter-specific headers for internal fetches
for (const [key, value] of Object.entries(internalFetchHeaders)) {
headers.set(key, value);
}
let body = param;
if (!(body instanceof FormData)) {
try {View on GitHub (pinned to d081033d5f)
Solutions
- Keep getActionContext()-using code in server-only modules and never import those modules from the client.
- Split shared helpers so server-context code is isolated from client-importable code.
- Use import type on the client to avoid pulling runtime action internals.
Example fix
// before - src/lib/auth.ts used by both handler and client
import { getActionContext } from 'astro:actions';
export function currentUserId() {
const ctx = getActionContext();
return ctx.locals.user?.id;
}
// after - src/lib/auth.server.ts (server only)
export function currentUserId() {
const ctx = getActionContext();
return ctx.locals.user?.id;
}
// client imports from a separate client-safe module instead Defensive patterns
Strategy: validation
Validate before calling
// Fail the build if a client-reachable module references getActionContext.
const CLIENT_FORBIDDEN = /getActionContext/;
for (const file of clientReachableFiles) {
if (CLIENT_FORBIDDEN.test(readFile(file))) {
throw new Error(`${file} uses server-only getActionContext() but is client-reachable`);
}
} Prevention
- Isolate getActionContext()-using helpers in *.server.ts files.
- Never import action-handler internals into client components.
- Use import type for cross-boundary type sharing.
When it happens
Trigger: Importing a module that calls getActionContext() (typically an action handler utility) into client code; sharing handler-side helpers between server and client without splitting them.
Common situations: A shared utils file used by both an action handler (calls getActionContext) and a client component; re-exporting handler internals through a barrel that the client imports.
Related errors
- [astro:actions] `defineAction()` unexpectedly used on the cl
- Action not found: ${path}
- [RSS] You can only glob entries within 'src/pages/' when pas
- BAD_REQUEST
- ActionCalledFromServerError
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/14f3ec11b7f78149.
Report an issue: GitHub.