{"record":{"id":"b2181f8965f4a23e","repo":"avajs/ava","slug":"cannot-record-snapshot-index-for-json-stringi-b2181f","errorCode":null,"errorMessage":"Cannot record snapshot ${index} for ${JSON.stringify(belongsTo)}, already exists","messagePattern":"Cannot record snapshot (.+?) for (.+?), already exists","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"lib/snapshot-manager.js","lineNumber":330,"sourceCode":"\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);\n\n\t\treturn () => { // Must be called in order!\n\t\t\tthis.hasChanges = true;","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/snapshot-manager.js#L312-L348","documentation":"This RangeError comes from AVA's snapshot manager (backed by ava's snapshot state machine). When an attempt (t.try()) records a serialized snapshot at a specific index, each index within a snapshot block may be recorded only once. If a snapshot at that index already has data, recording again would silently overwrite or duplicate existing snapshot state, so the manager refuses.","triggerScenarios":"Calling recordSerialized twice for the same snapshot index within one snapshot block — typically when t.try() (or deferRecord/skipSnapshot paths) records the same assertion's snapshot twice, or when attempt replay/reordering causes an index to be filled before a deferred recording lands.","commonSituations":"Test files where t.try() is used with snapshot assertions and the same attempt is executed or recorded twice; flaky attempt ordering when multiple t.try() calls run concurrently and both resolve into the same snapshot slot; hand-edited or out-of-sync .snap files changing expected index counts.","solutions":["Ensure each snapshot assertion inside a t.try() callback runs at most once per attempt (guard with the committed/discarded flags of the attempt).","Do not reuse a single t.try() attempt object to re-run snapshot assertions; create a fresh t.try() for each execution.","Regenerate snapshots with `ava --update-snapshots` if the .snap file has drifted out of sync with the test order.","Check for duplicate calls to t.snapshot() in shared helper functions invoked more than once inside one attempt."],"exampleFix":"// before\nconst attempt = t.try(tt => { tt.snapshot(value); });\nawait attempt;\nawait attempt; // records snapshot index twice -> RangeError\n\n// after\nconst attempt = t.try(tt => { tt.snapshot(value); });\nawait attempt;\n// run the assertion again in a NEW attempt if needed\nconst attempt2 = t.try(tt => { tt.snapshot(value); });\nawait attempt2;","handlingStrategy":"validation","validationCode":"function canRecord(snapshots, index) {\n  return index <= snapshots.length && (index === snapshots.length || !snapshots[index].data);\n}\nif (!canRecord(block.snapshots, index)) throw new RangeError(`Snapshot ${index} already recorded`);","typeGuard":"const isFreeSlot = (snapshots, index) =>\n  typeof index === 'number' && index >= 0 &&\n  (index >= snapshots.length || snapshots[index] == null || snapshots[index].data == null);","tryCatchPattern":"try {\n  attempt.commit();\n} catch (err) {\n  if (err instanceof RangeError && /already exists/.test(err.message)) {\n    // skip duplicate snapshot recording\n  } else throw err;\n}","preventionTips":["Run each snapshot assertion once per t.try() attempt","Never re-await or re-run a committed t.try() attempt","Keep .snap files in sync; regenerate with --update-snapshots after reordering t.snapshot() calls","Avoid invoking shared helpers containing t.snapshot() multiple times inside one attempt"],"tags":["snapshot","ava","t-try","duplicate-record"],"backgroundTag":"snapshot-already-exists","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}