withastro/astro · error · ActionInputError

BAD_REQUEST

BAD_REQUEST

Error message

Failed to validate: ${JSON.stringify(issues, null, 2)}

What it means

`AstroActionInputError` is the client-side error produced when a server action call fails input validation. The server's Zod issues are serialized back and this class re-throws them with `code: 'BAD_REQUEST'`; the message embeds the JSON of the issues, and the `fields` property groups issue messages by first path key for convenient form display.

Source

Thrown at packages/astro/src/actions/runtime/client.ts:140

		'issues' in error &&
		Array.isArray(error.issues)
	);
}

export class ActionInputError<T extends ErrorInferenceObject> extends ActionError {
	type = 'AstroActionInputError';

	// We don't expose all ZodError properties.
	// Not all properties will serialize from server to client,
	// and we don't want to import the full ZodError object into the client.

	issues: z.$ZodIssue[];
	fields: { [P in keyof T]?: string[] | undefined };

	constructor(issues: z.$ZodIssue[]) {
		super({
			message: `Failed to validate: ${JSON.stringify(issues, null, 2)}`,
			code: 'BAD_REQUEST',
		});
		this.issues = issues;
		this.fields = {};
		for (const issue of issues) {
			if (issue.path.length > 0) {
				const key = issue.path[0].toString() as keyof typeof this.fields;
				this.fields[key] ??= [];
				this.fields[key]?.push(issue.message);
			}
		}
	}
}

export function deserializeActionResult(res: SerializedActionResult): SafeResult<any, any> {
	if (res.type === 'error') {
		let json;
		try {
			json = JSON.parse(res.body);

View on GitHub (pinned to 52e6c34790)

Solutions

  1. Inspect `error.fields` (or the JSON in the message) to see exactly which field(s) and constraints failed
  2. Fix the payload to satisfy the schema, or adjust the schema (add `.optional()`, `z.coerce.number()`, etc.)
  3. Validate client-side before calling the action to give faster feedback, treating the server error as the backstop

Example fix

// schema expects z.object({ email: z.string().email() })
// before
const result = await actions.newsletter.subscribe({ email: 'not-an-email' });

// after
const result = await actions.newsletter.subscribe({ email: 'user@example.com' });
Defensive patterns

Strategy: validation

Validate before calling

import { z } from 'astro/zod';
const schema = z.object({ email: z.string().email(), age: z.coerce.number().int().min(0) });
const check = schema.safeParse(draft);
if (!check.success) {
  setFieldErrors(groupIssuesByField(check.error.issues));
} else {
  await actions.user.create(check.data);
}

Try / catch

try {
  await actions.user.create(input);
} catch (e) {
  if (e instanceof ActionError && e.type === 'AstroActionInputError') {
    // e.fields maps field name -> string[] of messages
    showFormErrors(e.fields);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling an action from the client (e.g. in a `<script>` via `actions.user.create(...)`) with input that violates the action's Zod schema: wrong type, missing required field, failing string constraints like email/min length.

Common situations: Form submissions where a field is empty or malformed; schema and UI drifting apart (schema gained a required field the form doesn't send); coercion surprises — sending a number as a string when the schema expects `z.number()`.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/8b9dc5725a9311f2. Report an issue: GitHub.