vitest-dev/vitest · error · TypeError
${utils.inspect(chain)} is not a `vi.when` instance
Error message
${utils.inspect(chain)} is not a `vi.when` instance What it means
The `.toHaveBeenExhausted` assertion (added by the mock chai plugin) is specifically for verifying that every behavior registered on a `vi.when(...)` chain has been consumed. It inspects the `$$vitest:when` symbol via `isWhenChain`; if the asserted object is not a `vi.when` instance it throws a `TypeError`. This prevents calling the matcher on a plain mock or arbitrary value where exhaustion is undefined.
Source
Thrown at packages/vitest/src/integrations/mock/chai.ts:13
import type { ChaiPlugin } from '@vitest/expect'
import { wrapAssertion } from '@vitest/expect'
import { isWhenChain } from './when'
export const MockPlugin: ChaiPlugin = (chai, utils) => {
utils.addMethod(
chai.Assertion.prototype,
'toHaveBeenExhausted',
wrapAssertion(utils, 'toHaveBeenExhausted', function (this) {
const chain = utils.flag(this, 'object')
if (!isWhenChain(chain)) {
throw new TypeError(
`${utils.inspect(chain)} is not a \`vi.when\` instance`,
)
}
const diagnostics = chain._getDiagnostics()
this.assert(
diagnostics.isExhausted,
`expected all behaviors to have been exhausted, but some remain:\n\n ${diagnostics.pendingBehaviors.replaceAll(/\n(?!\n)/g, '\n ')}`,
'expected at least one behavior to remain un-exhausted, but all were',
)
}),
)
}
View on GitHub (pinned to d568f8ce37)
Solutions
- Call `.toHaveBeenExhausted` on the value returned by `vi.when(spy)`, not on the spy itself.
- If you wanted to assert call counts on a plain mock, use `.toHaveBeenCalled()` / `.toHaveBeenCalledTimes(n)` instead.
- Ensure the `vi.when(...)` chain was actually assigned to a variable before asserting on it.
Example fix
// before const spy = vi.fn() vi.when(spy).calledWith(1).thenReturn(0) expect(spy).toHaveBeenExhausted() // after const w = vi.when(spy).calledWith(1).thenReturn(0) expect(w).toHaveBeenExhausted()
Defensive patterns
Strategy: type-guard
Validate before calling
import { isWhenChain } from 'vitest'
// assert on the vi.when handle, not the spy
const w = vi.when(spy).calledWith(1).thenReturn(0)
if (!isWhenChain(w)) throw new Error('expected a vi.when instance')
expect(w).toHaveBeenExhausted() Type guard
import { isWhenChain } from 'vitest'
// isWhenChain(input): input is When — exported from vitest Prevention
- Assign the `vi.when(...)` result to a variable and assert exhaustion on that variable.
- For plain mocks use `.toHaveBeenCalled*` instead of `.toHaveBeenExhausted`.
When it happens
Trigger: Calling `expect(someValue).toHaveBeenExhausted()` where `someValue` is a `vi.fn()`/`vi.spyOn()` mock, a raw function, an object, or any value not returned by `vi.when(spy)`.
Common situations: Confusing `vi.fn()` with `vi.when()`, or asserting exhaustion on the spy itself rather than the `vi.when` chain handle.
Related errors
- vi.when: the argument must be a mock function created with `
- vi.when: no behavior defined when called with [${args.map(ar
- .toContainHTML() expects a string value, got ${htmlText}
- ${matcherHint('.toBeSlowerThan')} expects the expected value
- vi.when: `times` option must be greater than 0
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/513e08af97aed934.json.
Report an issue: GitHub.