{"record":{"id":"5268c6a5ead573e3","repo":"avajs/ava","slug":"cannot-record-snapshot-index-for-json-stringi","errorCode":null,"errorMessage":"Cannot record snapshot ${index} for ${JSON.stringify(belongsTo)}, exceeds expected index of ${snapshots.length}","messagePattern":"Cannot record snapshot (.+?) for (.+?), exceeds expected index of (.+?)","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"lib/snapshot-manager.js","lineNumber":327,"sourceCode":"\t\t\t}\n\n\t\t\tthis.record(options);\n\t\t\treturn {pass: true};\n\t\t}\n\n\t\tconst actual = concordance.deserialize(Buffer.from(data.buffer, data.byteOffset, data.byteLength), concordanceOptions);\n\t\tconst expected = concordance.describe(options.expected, concordanceOptions);\n\t\tconst pass = concordance.compareDescriptors(actual, expected);\n\n\t\treturn {actual, expected, pass};\n\t}\n\n\trecordSerialized({data, label, belongsTo, index}) {\n\t\tconst block = this.newBlocksByTitle.get(belongsTo) ?? {snapshots: []};\n\t\tconst {snapshots} = block;\n\n\t\tif (index > snapshots.length) {\n\t\t\tthrow new RangeError(`Cannot record snapshot ${index} for ${JSON.stringify(belongsTo)}, exceeds expected index of ${snapshots.length}`);\n\t\t} else if (index < snapshots.length) {\n\t\t\tif (snapshots[index].data) {\n\t\t\t\tthrow new RangeError(`Cannot record snapshot ${index} for ${JSON.stringify(belongsTo)}, already exists`);\n\t\t\t}\n\n\t\t\tsnapshots[index] = {data, label};\n\t\t} else {\n\t\t\tsnapshots.push({data, label});\n\t\t}\n\n\t\tthis.newBlocksByTitle.set(belongsTo, block);\n\t}\n\n\tdeferRecord(options) {\n\t\tconst {expected, belongsTo, label, index} = options;\n\t\tconst descriptor = concordance.describe(expected, concordanceOptions);\n\t\tconst buffer = concordance.serialize(descriptor);\n\t\tconst data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/snapshot-manager.js#L309-L345","documentation":"During recording, AVA appends snapshots to a per-title block in order. recordSerialized() throws a RangeError when a snapshot's index is greater than the number of snapshots already collected for that belongsTo key, meaning the test reported snapshots out of order or skipped one, so the serialized output would have a gap.","triggerScenarios":"Calling recordSerialized (via deferRecord/skipSnapshot) with an index jumping ahead of snapshots.length for the same belongsTo group — e.g. a reporter/plugin emitting snapshot records out of sequence, or a test asserting snapshots non-deterministically so one index is skipped.","commonSituations":"Custom AVA reporters or integrations emitting snapshot records concurrently/out of order; failing tests that skip recording one snapshot while later ones still record; flaky tests with conditional snapshot assertions.","solutions":["Fix the source so snapshot records are emitted in ascending index order with no gaps for each belongsTo group","Make snapshot assertions unconditional or ensure a failed assertion still records its snapshot (use deferRecord) so indices stay contiguous","If using a custom reporter/plugin, buffer records and flush them sorted by index before calling recordSerialized"],"exampleFix":"// before (custom reporter, async out of order)\nrecords.forEach(r => recordSerialized(r));\n// after\nrecords.sort((a, b) => a.index - b.index).forEach(r => recordSerialized(r));","handlingStrategy":"try-catch","validationCode":"if (index > snapshots.length) {\n  throw new Error(`pre-check: snapshot index ${index} would leave a gap (expected ${snapshots.length})`);\n}","typeGuard":"function canRecordAt(block, index) {\n  return Number.isInteger(index) && index >= 0 && index <= block.snapshots.length;\n}","tryCatchPattern":"try {\n  recordSerialized({data, label, belongsTo, index});\n} catch (err) {\n  if (err instanceof RangeError && /exceeds expected index/.test(err.message)) {\n    // emit records in ascending order; re-run with records sorted by index\n  } else { throw err; }\n}","preventionTips":["Ensure snapshot records are emitted synchronously and in ascending index order per belongsTo group","In custom reporters, sort pending records by index before flushing","Keep snapshot assertions unconditional so skipped assertions do not create index gaps"],"tags":["snapshots","range-error","ordering"],"backgroundTag":"snapshot-index-out-of-order","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}