colinhacks/zod · error · Error

Synchronous parse encountered promise.

Error message

Synchronous parse encountered promise.

What it means

Thrown by _parseSync when the underlying _parse returns a value flagged as async (a Promise). Synchronous parse paths (`.parse`, `.safeParse`, `.spa` only when awaited-but-sync) cannot await, so zod refuses rather than silently returning `[object Promise]`.

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 912f0f51b0)

Solutions

  1. Switch the call site to the async API: `.parseAsync(data)` or `.spa(data)` (returns a Promise).
  2. If you must stay sync, remove the async refinement/transform or replace it with a sync check.
  3. Audit nested schemas — the async schema may be a field inside an object or array.

Example fix

// before
const schema = z.string().refine(async (v) => await checkDb(v));
schema.parse(value); // throws "Synchronous parse encountered promise."

// after
await schema.parseAsync(value);
// or
const res = await schema.spa(value);
Defensive patterns

Strategy: validation

Validate before calling

// Detect async schemas before calling sync parse
function isAsyncSchema(s: z.ZodTypeAny): boolean {
  // heuristic: walk _def for ZodEffects with async transform/refine
  return /\[z\.async\]|Promise/.test(s.description ?? "") || (s as any)._def?.effect != null;
}

Type guard

function canParseSync(s: z.ZodTypeAny): boolean {
  // No public flag; safest is to always use parseAsync for schemas that may contain effects.
  return true;
}

Try / catch

try { schema.parse(data); }
catch (e) {
  if (e instanceof Error && /encountered promise|Use \.parseAsync/.test(e.message)) {
    return await schema.parseAsync(data);
  }
  throw e;
}

Prevention

When it happens

Trigger: Using `.parse()` / `.safeParse()` (sync) on a schema that contains an async refinement (`.refine(async ...)`) or async transform (`.transform(async ...)`), or a schema that nests one.

Common situations: Adding an async validation (e.g. database uniqueness check) to an existing sync pipeline; refactoring a transform to be async without flipping the call site; testing an async schema with a sync assertion.

Related errors


AI-assisted analysis of colinhacks/zod@912f0f51b0 (2026-08-03). Data as JSON: /data/errors/566e941a4df632f0.json. Report an issue: GitHub.