vitest-dev/vitest · error · Error
expected must be a function, received ${typeof expected}
Error message
expected must be a function, received ${typeof expected} What it means
`toThrowErrorMatchingSnapshot` / `toThrowErrorMatchingInlineSnapshot` call `getError(expected, promise)` which expects the assertion's subject to be a function it can invoke to capture the thrown error. When not in a `resolves`/`rejects` promise context and the subject is not a function, there is nothing to execute, so it throws `expected must be a function, received <type>`.
Source
Thrown at packages/vitest/src/integrations/snapshot/chai.ts:30
import { getNames } from '../../utils/tasks'
let _client: SnapshotClient
export function getSnapshotClient(): SnapshotClient {
if (!_client) {
_client = new SnapshotClient({
isEqual: (received, expected) => {
return equals(received, expected, [iterableEquality, subsetEquality])
},
})
}
return _client
}
function getError(expected: () => void | Error, promise: string | undefined) {
if (typeof expected !== 'function') {
if (!promise) {
throw new Error(
`expected must be a function, received ${typeof expected}`,
)
}
// when "promised", it receives thrown error
return expected
}
try {
expected()
}
catch (e) {
return e
}
throw new Error('snapshot function didn\'t throw')
}
View on GitHub (pinned to d568f8ce37)
Solutions
- Wrap the code that should throw in a function: `expect(() => risky()).toThrowErrorMatchingSnapshot()`.
- For async rejection snapshots, use `await expect(promise).rejects.toThrowErrorMatchingSnapshot()` so the promise path is used.
- Ensure the matcher name actually matches your intent — use `toMatchSnapshot()` for non-throw values.
Example fix
// before expect(loadUser(-1)).toThrowErrorMatchingSnapshot() // after expect(() => loadUser(-1)).toThrowErrorMatchingSnapshot()
Defensive patterns
Strategy: type-guard
Validate before calling
function assertThrowsSnapshot(fn: () => unknown) {
if (typeof fn !== 'function') throw new TypeError('expected must be a function')
expect(fn).toThrowErrorMatchingSnapshot()
} Type guard
function isCallable(v: unknown): v is (...a: any[]) => any { return typeof v === 'function' } Prevention
- Always wrap the throwing code in `() => { ... }` for `toThrowError*Snapshot`.
- For async rejection snapshots use `await expect(p).rejects.toThrowErrorMatchingSnapshot()`.
When it happens
Trigger: Writing `expect(<non-function>).toThrowErrorMatchingSnapshot()` / `...InlineSnapshot()` outside of an async `resolves`/`rejects` chain — e.g. `expect(42).toThrowErrorMatchingSnapshot()` or `expect('err').toThrowErrorMatchingInlineSnapshot()`.
Common situations: Forgetting to wrap the throwing call in a function, or confusing `toThrowError*` matchers (which need a callable) with value matchers.
Related errors
- snapshot function didn't throw
- '${getAssertionName(obj)}' cannot be used without test conte
- You must provide an array or set to ${matcherHint('.toBeOneO
- Received value must be an object when the matcher has proper
- ${matcherHint('.toBeSlowerThan')} expects the expected value
AI-assisted analysis of vitest-dev/vitest@d568f8ce37 (2026-08-03).
Data as JSON: /data/errors/b7f699f68ed08614.json.
Report an issue: GitHub.