mastra-ai/mastra · error
Your schema is async, which is not supported. Please use a s
Error message
Your schema is async, which is not supported. Please use a sync schema.
What it means
Mastra validates request-context values against the tool's schema using the Standard Schema `validate` interface, which only supports synchronous validation. If the returned result is a Promise (i.e. the schema performs async checks like `z.refine` with async functions, async superRefine, or DB-backed checks), validation is silently impossible for this code path, so the library throws immediately. Note: the throw is inside a try/catch that returns `false` (rejecting the value), so the error is caught internally — but it originates here when an async schema is supplied.
Source
Thrown at packages/core/src/tools/tool.ts:39
* Marker to identify Mastra tools even when `instanceof` fails.
* This can happen in environments like Vite SSR where the same module
* may be loaded multiple times, creating different class instances.
* Uses Symbol.for() so the same symbol is shared across module copies.
* Follows the naming convention: <org>.<product>.<category>.<className>
*/
export const MASTRA_TOOL_MARKER = Symbol.for('mastra.core.tool.Tool');
type RequestContextEncoder = (values: Record<string, unknown>) => Record<string, unknown> | undefined;
type RequestContextInputValidator = (values: Record<string, unknown>) => boolean;
function getRequestContextInputValidator(schema: PublicSchema): RequestContextInputValidator {
const standardSchema = toStandardSchema(schema);
return values => {
try {
const result = standardSchema['~standard'].validate(values);
if (result instanceof Promise) {
throw new Error('Your schema is async, which is not supported. Please use a sync schema.');
}
return !('issues' in result) || !result.issues?.length;
} catch {
return false;
}
};
}
function getRequestContextEncoder(schema: PublicSchema | undefined): RequestContextEncoder | undefined {
if (!schema || (typeof schema !== 'object' && typeof schema !== 'function')) {
return undefined;
}
const encodableSchema = schema as {
safeEncode?: (value: unknown) => { success: boolean; data?: unknown };
'~standard'?: { vendor?: string };
};
if (encodableSchema['~standard']?.vendor !== 'zod' || typeof encodableSchema.safeEncode !== 'function') {View on GitHub (pinned to 75dd419e61)
Solutions
- Remove all async refinements/transforms from the request-context/tool input schema and keep it fully synchronous.
- Move the async check (e.g. uniqueness/DB lookup) into the tool's `execute` function, where awaits are allowed.
- If you need both sync shape validation and async business checks, split them: sync Standard Schema for the input, async logic in execute.
Example fix
// before
const schema = z.object({ email: z.string().refine(async e => !(await db.users.exists(e))) });
// after
const schema = z.object({ email: z.string().email() });
// check uniqueness inside execute instead:
async execute({ context }) {
if (await db.users.exists(context.email)) throw new Error('email taken');
} Defensive patterns
Strategy: validation
Validate before calling
function isSyncSchema(schema: unknown): boolean {
try {
const std = schema as { '~standard'?: { validate: (v: unknown) => unknown } };
return !(std?.['~standard']?.validate({}) instanceof Promise);
} catch {
return false;
}
}
// call before passing schema to Mastra Type guard
function isStandardSchema(v: unknown): v is { '~standard': { validate: (v: unknown) => { value?: unknown; issues?: readonly unknown[] } | Promise<unknown> } } {
return typeof v === 'object' && v !== null && '~standard' in v;
} Try / catch
try {
runWithSchema(schema);
} catch (e) {
if (e instanceof Error && e.message.includes('async, which is not supported')) {
throw new Error('Remove async refinements/transforms from the tool input schema.');
}
throw e;
} Prevention
- Never use `refine(async ...)`, async `superRefine`, or async `.transform()` in tool/request-context input schemas.
- Keep async business checks (DB/API lookups) inside tool `execute`, after sync shape validation.
- Add a unit test that runs the schema's `~standard.validate` and asserts a non-Promise result.
When it happens
Trigger: Passing a schema containing async refinements/transforms (e.g. `z.string().refine(async v => await checkDb(v))`, async `.superRefine`, or async `.transform`) as the request-context or tool input schema, so `standardSchema['~standard'].validate(values)` resolves to a Promise.
Common situations: Adding a uniqueness check against a database inside a refine; copying a schema from an API route that already uses async validators; migrating from plain z.object to schemas with async transforms for secret redaction.
Related errors
- Your schema is async, which is not supported. Please use a s
- ${label} contains an unsupported field.
- Invalid state update: ${messages}
- SchemaValidationError(field, this.formatErrors(result.error)
- INVALID_DATA_ITEM
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/85c05bc12e4d05ad.
Report an issue: GitHub.