{"record":{"id":"17ecef18e8aeb0a7","repo":"vitest-dev/vitest","slug":"snapshot-keys-must-end-with-a-number","errorCode":null,"errorMessage":"Snapshot keys must end with a number.","messagePattern":"Snapshot keys must end with a number\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/snapshot/src/port/utils.ts","lineNumber":24,"sourceCode":" */\n\nimport type { OptionsReceived as PrettyFormatOptions } from '@vitest/pretty-format'\nimport type { SnapshotData, SnapshotStateOptions } from '../types'\nimport type { SnapshotEnvironment } from '../types/environment'\nimport { format as prettyFormat } from '@vitest/pretty-format'\nimport { isObject } from '@vitest/utils/helpers'\nimport naturalCompare from 'natural-compare'\nimport { getSerializers } from './plugins'\n\n// TODO: rewrite and clean up\n\nexport function testNameToKey(testName: string, count: number): string {\n  return `${testName} ${count}`\n}\n\nexport function keyToTestName(key: string): string {\n  if (!/ \\d+$/.test(key)) {\n    throw new Error('Snapshot keys must end with a number.')\n  }\n\n  return key.replace(/ \\d+$/, '')\n}\n\nexport function getSnapshotData(\n  content: string | null,\n  options: SnapshotStateOptions,\n): {\n  data: SnapshotData\n  dirty: boolean\n} {\n  const update = options.updateSnapshot\n  const data = Object.create(null)\n  let snapshotContents = ''\n  let dirty = false\n\n  if (content != null) {","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/snapshot/src/port/utils.ts#L6-L42","documentation":"Vitest stores each snapshot under a key formed as `${testName} ${count}` (a space followed by one or more digits). keyToTestName reverses that format and asserts the key matches `/ \\d+$/`. If a snapshot key in a .snap file is missing its trailing numeric suffix, the parse aborts with this error. It almost always means the snapshot file was hand-edited or corrupted.","triggerScenarios":"Calling toMatchSnapshot/toMatchInlineSnapshot against a .snap file whose key was manually edited to remove the trailing number, or a .snap file generated by an incompatible/older snapshot format. Also triggered if a custom snapshot serializer or external tool rewrites keys without the count suffix.","commonSituations":"Manually editing .snap files to rename tests; merging snapshot files across branches where keys got mangled; running tests after a Vitest major version upgrade that changed key formatting.","solutions":["Delete the offending .snap file and re-run tests so Vitest regenerates every key with the correct ` name N` suffix.","Inspect the .snap file and fix the malformed key by appending ` 1` (space + count) to match the `testName N` format.","Check git history of the .snap file to find what rewrote the key and prevent that tool/process from modifying snapshots."],"exampleFix":"// before — .snap file contains:\n// exports[`my test`] = `\"value\"`;\n\n// after — append the numeric suffix:\n// exports[`my test 1`] = `\"value\"`;","handlingStrategy":"validation","validationCode":"function isValidSnapshotKey(key: string): boolean {\n  return / \\d+$/.test(key)\n}\n\n// before reading a .snap file's keys:\nif (!isValidSnapshotKey(key)) {\n  // regenerate the snapshot instead of parsing\n}","typeGuard":"function isWellFormedSnapshotKey(key: string): boolean {\n  return typeof key === 'string' && / \\d+$/.test(key)\n}","tryCatchPattern":null,"preventionTips":["Never hand-edit .snap files; always update via Vitest's snapshot update flow (vitest -u).","Add .snap files to .gitattributes as binary or lock them to prevent accidental merges.","Run vitest --no-watch after upgrading Vitest major versions to regenerate snapshots."],"tags":["snapshot","file-format","data-corruption"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}