vitest-dev/vitest · error · TypeError

Async schema validation is not supported in asymmetric match

Error message

Async schema validation is not supported in asymmetric matchers.

What it means

Thrown as a TypeError inside SchemaMatching.asymmetricMatch when the schema's validate() returns a Promise. Asymmetric matchers run synchronously within the equality check, so an async schema cannot be evaluated; Vitest refuses to silently return a wrong result.

Source

Thrown at packages/expect/src/jest-asymmetric-matchers.ts:416

export class SchemaMatching extends AsymmetricMatcher<StandardSchemaV1<unknown, unknown>> {
  private result: StandardSchemaV1.Result<unknown> | undefined

  constructor(sample: StandardSchemaV1<unknown, unknown>, inverse = false) {
    if (!isStandardSchema(sample)) {
      throw new TypeError(
        'SchemaMatching expected to receive a Standard Schema.',
      )
    }
    super(sample, inverse)
  }

  asymmetricMatch(other: unknown): boolean {
    const result = this.sample['~standard'].validate(other)

    // Check if the result is a Promise (async validation)
    if (result instanceof Promise) {
      throw new TypeError('Async schema validation is not supported in asymmetric matchers.')
    }

    this.result = result
    const pass = !this.result.issues || this.result.issues.length === 0

    return this.inverse ? !pass : pass
  }

  toString() {
    return `Schema${this.inverse ? 'Not' : ''}Matching`
  }

  getExpectedType() {
    return 'object'
  }

  toAsymmetricMatcher(): string {
    const { utils } = this.getMatcherContext()

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Use a synchronous schema variant for asymmetric matching (remove async refinements).
  2. Validate explicitly with await schema['~standard'].validate(value) and assert on the result instead of using schemaMatching.
  3. Refactor the async logic out of the schema used for matching.

Example fix

// before
const schema = z.object({ email: z.string().email().refine(async () => checkDb()) })
expect(body).toEqual(expect.schemaMatching(schema)) // throws: async validate
// after
const result = await schema['~standard'].validate(body)
expect(result.issues ?? []).toEqual([])
Defensive patterns

Strategy: validation

Validate before calling

// detect async validation before using schemaMatching
function isSyncSchema(schema: any): boolean {
  const probe = {}
  const result = schema['~standard'].validate(probe)
  return !(result instanceof Promise)
}
if (!isSyncSchema(schema)) {
  throw new TypeError('Use a sync schema for schemaMatching, or await validate() manually')
}

Type guard

function isSyncValidator(schema: any): boolean {
  // best-effort: probe with a sentinel once and cache
  const r = schema['~standard'].validate(undefined)
  return !(r instanceof Promise)
}

Try / catch

try {
  expect(value).toEqual(expect.schemaMatching(schema))
} catch (e) {
  if (/Async schema validation/i.test(String((e as Error).message))) {
    const result = await schema['~standard'].validate(value)
    expect(result.issues ?? []).toEqual([])
  } else throw e
}

Prevention

When it happens

Trigger: Using expect.schemaMatching(schema) where schema['~standard'].validate(value) returns a Promise (the validator does I/O, async refinements, or DB lookups). The match throws at comparison time, not construction.

Common situations: A zod/valibot schema with async refine/superRefine or async piped validators; a custom Standard Schema whose validate is async; moving a schema that worked in expect() into an asymmetric context.

Related errors


AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03). Data as JSON: /data/errors/dc2501d4c85193fa.json. Report an issue: GitHub.