vitest-dev/vitest · error · TestSyntaxError

'${getAssertionName(obj)}' cannot be used with 'test.fails'

Error message

'${getAssertionName(obj)}' cannot be used with 'test.fails'

What it means

`getTest` rejects snapshot matchers inside a `test.fails(...)` block by throwing a `TestSyntaxError`. Snapshot matchers record their result into the snapshot file as a side effect; under `test.fails` the test is expected to fail, but a passing snapshot write would still mutate disk state, producing confusing semantics. Vitest forbids the combination outright.

Source

Thrown at packages/vitest/src/integrations/snapshot/chai.ts:71

    testId: test.id,
  }
}

function getAssertionName(assertion: Chai.Assertion): string {
  const name = chai.util.flag(assertion, '_name') as string | undefined
  if (!name) {
    throw new Error('Assertion name is not set. This is a bug in Vitest. Please, open a new issue with reproduction.')
  }
  return name
}

function getTest(obj: Chai.Assertion) {
  const test = chai.util.flag(obj, 'vitest-test') as Test | undefined
  if (!test) {
    throw new Error(`'${getAssertionName(obj)}' cannot be used without test context`)
  }
  if (test.fails) {
    throw new TestSyntaxError(`'${getAssertionName(obj)}' cannot be used with 'test.fails'`)
  }
  return test
}

function validateAssertion(assertion: Chai.Assertion): void {
  if (chai.util.flag(assertion, 'negate')) {
    throw new Error(`${getAssertionName(assertion)} cannot be used with "not"`)
  }
}

export const SnapshotPlugin: ChaiPlugin = (chai, utils) => {
  for (const key of ['matchSnapshot', 'toMatchSnapshot']) {
    utils.addMethod(
      chai.Assertion.prototype,
      key,
      wrapAssertion(utils, key, function (
        this,
        propertiesOrHint?: object | string,

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Remove `test.fails` and instead assert the expected failure explicitly (e.g. `expect(() => ...).toThrow(...)`).
  2. Move the snapshot assertion into a separate non-`fails` test that documents the current/expected output.
  3. If the test genuinely should fail, do not use a writing snapshot matcher there.

Example fix

// before
test.fails('rejects invalid', () => {
  expect(parse('bad')).toMatchSnapshot()
})
// after
test('rejects invalid', () => {
  expect(() => parse('bad')).toThrow(/invalid/)
})
Defensive patterns

Strategy: validation

Validate before calling

// do not combine test.fails with writing snapshot matchers
// if you need to snapshot, use a regular test()

Prevention

When it happens

Trigger: Placing `expect(...).toMatchSnapshot()` / `.toMatchInlineSnapshot()` / `.toMatchFileSnapshot()` / `toThrowErrorMatching*Snapshot()` inside a `test.fails('...', () => { ... })` callback.

Common situations: Marking an error-path test with `test.fails` while also snapshotting, or converting a passing snapshot test to `test.fails` during debugging.

Related errors


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