withastro/astro · error · AstroError
`getActionState()` could not find a state object.
Error message
`getActionState()` could not find a state object.
What it means
Thrown by @astrojs/react's `getActionState()` when the form request is valid but the `_astroActionState` field is absent from the parsed `FormData`. That field is injected by the `withState()` wrapper so the server can recover the prior state passed to `useActionState()`.
Source
Thrown at packages/integrations/react/src/actions.ts:58
return callback;
}
/**
* Retrieve the state object from your action handler when using `useActionState()`.
* To ensure this state is retrievable, use the {@linkcode withState} helper.
*/
export async function getActionState<T>({ request }: { request: Request }): Promise<T> {
const contentType = request.headers.get('Content-Type');
if (!contentType || !isFormRequest(contentType)) {
throw new AstroError(
'`getActionState()` must be called with a form request.',
"Ensure your action uses the `accept: 'form'` option.",
);
}
const formData = await request.clone().formData();
const state = formData.get('_astroActionState')?.toString();
if (!state) {
throw new AstroError(
'`getActionState()` could not find a state object.',
'Ensure your action was passed to `useActionState()` with the `withState()` wrapper.',
);
}
return JSON.parse(state) as T;
}
const formContentTypes = ['application/x-www-form-urlencoded', 'multipart/form-data'];
function isFormRequest(contentType: string) {
// Split off parameters like charset or boundary
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type#content-type_in_html_forms
const type = contentType.split(';')[0].toLowerCase();
return formContentTypes.some((t) => type === t);
}
/**View on GitHub (pinned to d081033d5f)
Solutions
- Wrap the action with `withState()` before handing it to `useActionState()`: `const [state, dispatch] = useActionState(withState(myAction), initial);`.
- Confirm the action is invoked through the wrapper, not the original function reference.
- If posting manually, include a `_astroActionState` field (JSON-stringified state) in the FormData.
Example fix
// before
const [state, dispatch] = useActionState(myAction, initialState);
// after
import { withState } from '@astrojs/react/actions';
const [state, dispatch] = useActionState(withState(myAction), initialState); Defensive patterns
Strategy: validation
Validate before calling
const formData = await request.clone().formData();
if (!formData.has('_astroActionState')) {
throw new Error('Action not wired through withState(); skipping getActionState.');
} Try / catch
try { const state = await getActionState({ request }); } catch (e) { if (/could not find a state object/) { /* return initial state */ } else throw e; } Prevention
- Always pass actions through `withState()` before `useActionState`.
- Unit-test the action end-to-end with a real form post.
- Document the requirement in the action's JSDoc.
When it happens
Trigger: Calling `getActionState` on an action that was NOT wrapped with `withState()` before being passed to React's `useActionState()`. A hand-built form that posts to the action without the hidden `_astroActionState` input. The wrapper's `formData.set('_astroActionState', ...)` was skipped because the callback branch returned early.
Common situations: Passing the raw action to `useActionState` instead of `withState(action)`. Using a custom form submission that bypasses React's progressive-enhancement hidden field injection.
Related errors
- `getActionState()` must be called with a form request.
- [astro:actions] `defineAction()` unexpectedly used on the cl
- [astro:actions] `getActionContext()` unexpectedly used on th
- BAD_REQUEST
- ActionCalledFromServerError
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/2875fe82b4211a28.
Report an issue: GitHub.