vitest-dev/vitest · error · Error

invalid snapshot serializer file ${file}. Must export a defa

Error message

invalid snapshot serializer file ${file}. Must export a default object

What it means

Thrown by loadSnapshotSerializers when a file listed in `config.snapshotSerializers` does not have a default export that is a non-null object. Each serializer file must `export default { test, serialize/print }`. The default export is the serializer object Vitest registers via @vitest/snapshot's addSerializer.

Source

Thrown at packages/vitest/src/runtime/setup-common.ts:74

  }
  else {
    throw new Error(
      `invalid diff config file ${config.diff}. Must have a default export with config object`,
    )
  }
}

export async function loadSnapshotSerializers(
  config: SerializedConfig,
  moduleRunner: PublicModuleRunner,
): 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
    }),
  )

View on GitHub (pinned to d568f8ce37)

Solutions

  1. Use `export default { test, serialize }` in the serializer file.
  2. Confirm the path in `config.snapshotSerializers` resolves to the serializer file.
  3. Drop the file from snapshotSerializers if it was added by mistake.
  4. Migrate named-export serializers to default exports.

Example fix

// before (./my-serializer.js)
export const test = () => {}
export const serialize = () => {}

// after
export default {
  test: val => typeof val === 'MyType',
  serialize: (val, config, indent, depth, refs) => `MyType(${val.value})`,
}
Defensive patterns

Strategy: type-guard

Validate before calling

import * as mod from './my-serializer.js'
if (!mod.default || typeof mod.default !== 'object') {
  throw new Error('serializer must `export default { test, serialize|print }`')
}

Type guard

function isSerializerFile(m: any): m is { default: object } {
  return Boolean(m && m.default && typeof m.default === 'object')
}

Prevention

When it happens

Trigger: Listing a path under `test.snapshotSerializers: ['./my-serializer.js']` where the file has no default export, exports default as null, or exports default as a primitive/function. Importing a serializer that uses the older named-export convention.

Common situations: Porting a Jest-style snapshot serializer that used `module.exports = { ... }` incorrectly, or that used named exports. Forgetting `default` when converting CJS to ESM. Pointing at a util file that exports helper functions, not a serializer.

Related errors


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