avajs/ava · error · RangeError

Cannot record snapshot ${index} for ${JSON.stringify(belongs

Error message

Cannot record snapshot ${index} for ${JSON.stringify(belongsTo)}, exceeds expected index of ${snapshots.length}

What it means

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.

Source

Thrown at lib/snapshot-manager.js:327

			}

			this.record(options);
			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);

View on GitHub (pinned to bbfd946322)

Solutions

  1. Fix the source so snapshot records are emitted in ascending index order with no gaps for each belongsTo group
  2. Make snapshot assertions unconditional or ensure a failed assertion still records its snapshot (use deferRecord) so indices stay contiguous
  3. If using a custom reporter/plugin, buffer records and flush them sorted by index before calling recordSerialized

Example fix

// before (custom reporter, async out of order)
records.forEach(r => recordSerialized(r));
// after
records.sort((a, b) => a.index - b.index).forEach(r => recordSerialized(r));
Defensive patterns

Strategy: try-catch

Validate before calling

if (index > snapshots.length) {
  throw new Error(`pre-check: snapshot index ${index} would leave a gap (expected ${snapshots.length})`);
}

Type guard

function canRecordAt(block, index) {
  return Number.isInteger(index) && index >= 0 && index <= block.snapshots.length;
}

Try / catch

try {
  recordSerialized({data, label, belongsTo, index});
} catch (err) {
  if (err instanceof RangeError && /exceeds expected index/.test(err.message)) {
    // emit records in ascending order; re-run with records sorted by index
  } else { throw err; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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