colinhacks/zod · error · Error
Async refinement encountered during synchronous parse…
Error message
Async refinement encountered during synchronous parse operation. Use .parseAsync instead.
What it means
Thrown at packages/zod/src/v3/types.ts:4380 during a synchronous parse when a refinement's return value is a Promise. Zod detects (result instanceof Promise) inside the sync branch of the refinement effect and aborts, because awaiting that Promise would require the async parser. The error message names the exact escape hatch: switch to .parseAsync().
Solutions
- Switch every consumer of the schema to `await schema.parseAsync(data)` / `await schema.safeParseAsync(data)`.
- If a consumer must stay sync, rewrite the refinement to be synchronous (precompute the lookup, or cache the result).
- Split the schema: keep a sync schema for fast checks and run the async refinement only where you can await.
- Audit all .refine/.superRefine callbacks on the schema for a returned Promise.
Example fix
// before
const schema = z.object({
email: z.string().refine(async (v) => !(await isBlacklisted(v))),
});
schema.parse(input); // throws: Async refinement encountered...
// after
await schema.parseAsync(input); Defensive patterns
Strategy: validation
Validate before calling
import { ZodType, ZodFirstPartyTypeKind } from 'zod';
function findAsyncRefinements(schema: ZodType, path: string[] = []): string[] {
const def = (schema as any)._def;
if (!def) return [];
if (def.typeName === ZodFirstPartyTypeKind.ZodEffects && def.effect?.type === 'refinement') {
const src = def.effect.refinement?.toString() ?? '';
if (/\basync\b/.test(src)) return [path.join('.') || '(root)'];
return findAsyncRefinements(def.schema, path);
}
return [];
} Type guard
null
Try / catch
null
Prevention
- Switch all consumers of an async-refined schema to .parseAsync()/.safeParseAsync().
- Run a repo-wide grep for `.refine(async` and `.superRefine(async` when adding async checks.
- Keep sync schemas sync: do I/O before parse and pass results in as data.
- Document in module JSDoc which schemas require the async parse path.
When it happens
Trigger: Defining `z.string().refine(async (v) => await isValid(v))` and then parsing with `.parse()` or `.safeParse()` (the sync path). The refine callback returns a Promise, the sync branch in executeRefinement sees it, and throws.
Common situations: Adding a DB/HTTP-backed refinement to a schema that callers parse synchronously; mixing sync and async refinements in one schema; refactoring a refinement from sync to async without updating call sites; shared schema modules used by both sync and async callers.
Related errors
- Asynchronous transform encountered during synchronous parse…
- Synchronous parse encountered promise.
- Async schemas not supported in object keys currently
- Custom types cannot be represented in JSON Schema
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/935607010faa81ec.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v3/types.ts:4380
const result = this._def.schema._parseSync({
data: processed,
path: ctx.path,
parent: ctx,
});
if (result.status === "aborted") return INVALID;
if (result.status === "dirty") return DIRTY(result.value);
if (status.value === "dirty") return DIRTY(result.value);
return result;
}
}
if (effect.type === "refinement") {
const executeRefinement = (acc: unknown): any => {
const result = effect.refinement(acc, checkCtx);
if (ctx.common.async) {
return Promise.resolve(result);
}
if (result instanceof Promise) {
throw new Error("Async refinement encountered during synchronous parse operation. Use .parseAsync instead.");
}
return acc;
};
if (ctx.common.async === false) {
const inner = this._def.schema._parseSync({
data: ctx.data,
path: ctx.path,
parent: ctx,
});
if (inner.status === "aborted") return INVALID;
if (inner.status === "dirty") status.dirty();
// return value is ignored
executeRefinement(inner.value);
return { status: status.value, value: inner.value };
} else {
return this._def.schema._parseAsync({ data: ctx.data, path: ctx.path, parent: ctx }).then((inner) => {View on GitHub (pinned to 2d90846af9)