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

  1. Ensure each snapshot assertion inside a t.try() callback runs at most once per attempt (guard with the committed/discarded flags of the attempt).
  2. Do not reuse a single t.try() attempt object to re-run snapshot assertions; create a fresh t.try() for each execution.
  3. Regenerate snapshots with `ava --update-snapshots` if the .snap file has drifted out of sync with the test order.
  4. 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

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


AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02). Data as JSON: /api/errors/b2181f8965f4a23e. Report an issue: GitHub.