colinhacks/zod · error · Error
Synchronous parse encountered promise.
Error message
Synchronous parse encountered promise.
What it means
Thrown by _parseSync at packages/zod/src/v3/types.ts:213 when a schema's internal _parse returns a Promise (an async result) but a synchronous code path demanded a value now. Zod's sync parser cannot await promises, so it aborts rather than silently returning garbage. The typical upstream cause is a schema containing an async refinement or async transform being driven through a sync API like .parse(), .safeParse(), or .spa() in v3.
Solutions
- Switch the call site to the async API: `await schema.parseAsync(data)` or `await schema.safeParseAsync(data)`.
- If the call site must stay sync, replace the async refine/transform with a synchronous check.
- Audit every `.refine()` and `.transform()` on the schema to confirm none returns a Promise.
- If you control the custom ZodType, ensure _parse returns a synchronous result when parsed synchronously, or only expose the async path.
Example fix
// before const schema = z.string().refine(async (v) => await checkDb(v)); schema.parse(input); // throws: Synchronous parse encountered promise. // after const schema = z.string().refine(async (v) => await checkDb(v)); await schema.parseAsync(input);
Defensive patterns
Strategy: validation
Validate before calling
import { ZodType, ZodFirstPartyTypeKind } from 'zod';
// Best-effort check: walk the schema definition for refine/transform effects.
function hasAsyncEffect(schema: ZodType): boolean {
const def = (schema as any)._def;
if (!def) return false;
if (def.typeName === ZodFirstPartyTypeKind.ZodEffects) {
const eff = def.effect;
if (eff?.type === 'refinement' || eff?.type === 'transform') {
// heuristic: function source contains 'async'
const src = eff.refinement?.toString() || eff.transform?.toString() || '';
if (/\basync\b/.test(src)) return true;
}
return hasAsyncEffect(def.schema);
}
// recurse into common containers as needed
return false;
} Type guard
null
Try / catch
null
Prevention
- Treat any .refine(async ...) or .transform(async ...) as a hard signal to switch all callers to .parseAsync().
- Run a repo-wide grep for 'async' inside .refine()/.transform() callbacks when adding the async path.
- Document async schemas in their module JSDoc so callers know to await.
- Prefer safeParseAsync() in library code that accepts user-supplied schemas.
When it happens
Trigger: Calling `.parse()` or `.safeParse()` (synchronous) on a schema that has a `.refine(async ...)` or `.transform(async ...)` where the inner function returns a Promise. Also reached when a custom ZodType subclass overrides _parse to return a Promise but is then parsed via _parseSync.
Common situations: Writing a refinement that hits a database or HTTP endpoint and returns a Promise, then forgetting to switch the call site to .parseAsync(); adding an async transform during refactor without updating callers; library code that calls .parse() generically on user-supplied schemas that may be async.
Related errors
- Async refinement encountered during synchronous parse…
- Asynchronous transform encountered during synchronous parse…
- Async schemas not supported in object keys currently
- Custom types cannot be represented in JSON Schema
- Transforms cannot be represented in JSON Schema
AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11).
Data as JSON: /api/errors/566e941a4df632f0.
Report an issue: GitHub.
Appendix: source
Thrown at packages/zod/src/v3/types.ts:213
return {
status: new ParseStatus(),
ctx: {
common: input.parent.common,
data: input.data,
parsedType: getParsedType(input.data),
schemaErrorMap: this._def.errorMap,
path: input.path,
parent: input.parent,
},
};
}
_parseSync(input: ParseInput): SyncParseReturnType<Output> {
const result = this._parse(input);
if (isAsync(result)) {
throw new Error("Synchronous parse encountered promise.");
}
return result;
}
_parseAsync(input: ParseInput): AsyncParseReturnType<Output> {
const result = this._parse(input);
return Promise.resolve(result);
}
parse(data: unknown, params?: util.InexactPartial<ParseParams>): Output {
const result = this.safeParse(data, params);
if (result.success) return result.data;
throw result.error;
}
safeParse(data: unknown, params?: util.InexactPartial<ParseParams>): SafeParseReturnType<Input, Output> {
const ctx: ParseContext = {
common: {View on GitHub (pinned to 2d90846af9)