avajs/ava · error · RangeError
Cannot record snapshot ${index} for ${JSON.stringify(belongs
Error message
Cannot record snapshot ${index} for ${JSON.stringify(belongsTo)}, already exists What it means
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.
Source
Thrown at lib/snapshot-manager.js:330
return {pass: true};
}
const actual = concordance.deserialize(Buffer.from(data.buffer, data.byteOffset, data.byteLength), concordanceOptions);
const expected = concordance.describe(options.expected, concordanceOptions);
const pass = concordance.compareDescriptors(actual, expected);
return {actual, expected, pass};
}
recordSerialized({data, label, belongsTo, index}) {
const block = this.newBlocksByTitle.get(belongsTo) ?? {snapshots: []};
const {snapshots} = block;
if (index > snapshots.length) {
throw new RangeError(`Cannot record snapshot ${index} for ${JSON.stringify(belongsTo)}, exceeds expected index of ${snapshots.length}`);
} else if (index < snapshots.length) {
if (snapshots[index].data) {
throw new RangeError(`Cannot record snapshot ${index} for ${JSON.stringify(belongsTo)}, already exists`);
}
snapshots[index] = {data, label};
} else {
snapshots.push({data, label});
}
this.newBlocksByTitle.set(belongsTo, block);
}
deferRecord(options) {
const {expected, belongsTo, label, index} = options;
const descriptor = concordance.describe(expected, concordanceOptions);
const buffer = concordance.serialize(descriptor);
const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
return () => { // Must be called in order!
this.hasChanges = true;View on GitHub (pinned to bbfd946322)
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.
Example fix
// before
const attempt = t.try(tt => { tt.snapshot(value); });
await attempt;
await attempt; // records snapshot index twice -> RangeError
// after
const attempt = t.try(tt => { tt.snapshot(value); });
await attempt;
// run the assertion again in a NEW attempt if needed
const attempt2 = t.try(tt => { tt.snapshot(value); });
await attempt2; Defensive patterns
Strategy: validation
Validate before calling
function canRecord(snapshots, index) {
return index <= snapshots.length && (index === snapshots.length || !snapshots[index].data);
}
if (!canRecord(block.snapshots, index)) throw new RangeError(`Snapshot ${index} already recorded`); Type guard
const isFreeSlot = (snapshots, index) => typeof index === 'number' && index >= 0 && (index >= snapshots.length || snapshots[index] == null || snapshots[index].data == null);
Try / catch
try {
attempt.commit();
} catch (err) {
if (err instanceof RangeError && /already exists/.test(err.message)) {
// skip duplicate snapshot recording
} else throw err;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Expected an implementation.
- `t.try()` titles must be strings
- Duplicate test title: ${attemptTitle}
- `t.snapshot()` can only be used in tests
- The snapshot assertion message must be a non-empty string
AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02).
Data as JSON: /api/errors/b2181f8965f4a23e.
Report an issue: GitHub.