{"id":"f65b20dadb390acc","repo":"jestjs/jest","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/jest-snapshot-utils/src/utils.ts","lineNumber":127,"sourceCode":"  key.replaceAll(/\\\\r\\\\n|\\\\r|\\\\n/g, match => {\n    switch (match) {\n      case '\\\\r\\\\n':\n        return '\\r\\n';\n      case '\\\\r':\n        return '\\r';\n      case '\\\\n':\n        return '\\n';\n      default:\n        return match;\n    }\n  });\n\nexport const testNameToKey = (testName: string, count: number): string =>\n  `${normalizeTestNameForKey(testName)} ${count}`;\n\nexport const keyToTestName = (key: string): string => {\n  if (!/ \\d+$/.test(key)) {\n    throw new Error('Snapshot keys must end with a number.');\n  }\n  const testNameWithoutCount = key.replace(/ \\d+$/, '');\n  return denormalizeTestNameFromKey(testNameWithoutCount);\n};\n\nexport const getSnapshotData = (\n  snapshotPath: string,\n  update: Config.SnapshotUpdateState,\n): {\n  data: SnapshotData;\n  dirty: boolean;\n} => {\n  const data = Object.create(null);\n  let snapshotContents = '';\n  let dirty = false;\n\n  if (fs.existsSync(snapshotPath)) {\n    try {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-snapshot-utils/src/utils.ts#L109-L145","documentation":"Thrown by `keyToTestName` in @jest/snapshot-utils (utils.ts:125-128) when a snapshot file key does not end with ` <number>`. Every snapshot key is built by `testNameToKey` as `${normalizedTestName} ${count}` (utils.ts:122-123); the trailing count is what lets `keyToTestName` reverse the mapping. A key without it means the snapshot file is corrupt or hand-edited.","triggerScenarios":"A `*.snap` file with a key like `exports['my test'] = ...` (missing the trailing ` 1`). Calling `keyToTestName('badKey')` directly. Snapshot files written by non-Jest tooling.","commonSituations":"Manual edits to `*.snap` files. Merge conflicts in snapshots that dropped the count. Custom serializers/reporters that wrote keys incorrectly.","solutions":["Delete the offending snapshot file and re-run with `--ci=false` (or `-u`) so Jest regenerates valid keys.","Fix the key by appending ` <n>` (e.g. `'my test' 1`) if you must edit by hand.","Stop hand-editing `*.snap` files; treat them as generated artifacts."],"exampleFix":"// before — snapshots/my.test.snap\nexports['my test'] = `\"value\"`;\n\n// after\nexports['my test 1'] = `\"value\"`;","handlingStrategy":"try-catch","validationCode":"function isKeyValid(key: string): boolean {\n  return / \\d+$/.test(key);\n}\nObject.keys(snapshotData).forEach(k => {\n  if (!isKeyValid(k)) throw new Error(`Corrupt snapshot key: ${k}`);\n});","typeGuard":"function isValidSnapshotKey(key: unknown): key is string {\n  return typeof key === 'string' && / \\d+$/.test(key);\n}","tryCatchPattern":"try {\n  keyToTestName(k);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Snapshot keys must end with a number.') {\n    // delete the snapshot file and regenerate with -u\n  } else throw e;\n}","preventionTips":["Never edit *.snap files by hand; regenerate them via the test runner.","Add *.snap files to .gitattributes as binary-ish to discourage merge conflicts.","Run `jest --ci` in CI to catch corrupt snapshots before they ship."],"tags":["snapshot","snapshot-file","corrupt-file"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}