vitest-dev/vitest · error · TypeError
invalid snapshot serializer in
Error message
invalid snapshot serializer in ${file}. Must have a 'test' method along with either a 'serialize' or 'print' method. What it means
Thrown (as TypeError) by loadSnapshotSerializers after the default export is confirmed to be an object, if that object does not satisfy the SnapshotSerializer interface — specifically it must have a `test` function AND at least one of `serialize` or `print`. This mirrors Jest's serializer contract used by @vitest/snapshot's addSerializer.
Solutions
- Implement all required methods: a `test(val)` function plus either `serialize(val, config, indentation, depth, refs, printer)` or `print(val, printer)`.
- Use `serialize` for full custom formatting; use `print` only when delegating to the built-in printer.
- Confirm the exported object is the serializer itself, not settings for one.
Example fix
// before
export default { test: 'yes' }
// after
export default {
test: v => v?.constructor?.name === 'Money',
serialize: (val, config, indentation, depth, refs, printer) => {
return printer(`$${val.amount}`, config, indentation, depth, refs)
},
} Defensive patterns
Strategy: type-guard
Validate before calling
function assertSerializer(v: unknown) {
const o = v as any
if (typeof o?.test !== 'function') throw new TypeError('serializer.test must be a function')
if (typeof o?.serialize !== 'function' && typeof o?.print !== 'function') {
throw new TypeError('serializer must have serialize or print')
}
} Type guard
type Serializer = { test: Function; serialize?: Function; print?: Function }
function isSerializer(v: unknown): v is Serializer {
const o = v as any
return typeof o?.test === 'function'
&& (typeof o?.serialize === 'function' || typeof o?.print === 'function')
} Prevention
- Mirror Jest's serializer contract exactly: test + (serialize | print).
- Write a smoke test importing each serializer file and asserting the method shape.
- Prefer serialize over print unless delegating to the built-in printer.
When it happens
Trigger: A snapshotSerializers entry default-exports an object that is missing `test`, missing both `serialize` and `print`, or where those keys are not functions (e.g. a plain config object was exported by mistake).
Common situations: Exporting a configuration object instead of a serializer; partially implementing the serializer interface; copy-paste errors that drop a method; version drift where a serializer was written against an older shape.
Related errors
- invalid snapshot serializer file
- "snapshotFormat.compareKeys" function is not supported.
- All browser instances within a project must use the same…
- "browser.instances" was set in the config, but the array is…
- Each tag defined in "test.tags" must have a "name"…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/9d9f4acbe6e666f6.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/runtime/setup-common.ts:85
): Promise<void> {
const files = config.snapshotSerializers
const snapshotSerializers = await Promise.all(
files.map(async (file) => {
const mo = await moduleRunner.import(file)
if (!mo || typeof mo.default !== 'object' || mo.default === null) {
throw new Error(
`invalid snapshot serializer file ${file}. Must export a default object`,
)
}
const config = mo.default
if (
typeof config.test !== 'function'
|| (typeof config.serialize !== 'function'
&& typeof config.print !== 'function')
) {
throw new TypeError(
`invalid snapshot serializer in ${file}. Must have a 'test' method along with either a 'serialize' or 'print' method.`,
)
}
return config as SnapshotSerializer
}),
)
snapshotSerializers.forEach(serializer => addSerializer(serializer))
}
View on GitHub (pinned to 1fa9837ec2)