avajs/ava · error · Error

Duplicate test title: ${title.value}

Error message

Duplicate test title: ${title.value}

What it means

The AVA test runner throws this when two tests are declared with the exact same title. During test declaration (synchronously at file load) every test title is registered via registerUniqueTitle(); a second registration of an equal title returns false and the constructor throws. Unique titles are required so snapshots and --match patterns can unambiguously identify tests.

Source

Thrown at lib/runner.js:116

			}

			metadata.taskIndex = this.nextTaskIndex++;

			const {args, implementation, title} = parseTestArgs(testArgs);

			metadata.selected &&= this.checkSelectedByLineNumbers?.() ?? true;

			if (metadata.todo) {
				if (implementation) {
					throw new TypeError('`todo` tests are not allowed to have an implementation. Use `test.skip()` for tests with an implementation.');
				}

				if (!title.raw) { // Either undefined or a string.
					throw new TypeError('`todo` tests require a title');
				}

				if (!this.registerUniqueTitle(title.value)) {
					throw new Error(`Duplicate test title: ${title.value}`);
				}

				// --match selects TODO tests.
				metadata.selected &&= isTitleMatch(title.value, this.matchPatterns);

				this.tasks.todo.push({title: title.value, metadata});
				this.emit('stateChange', {
					type: 'declared-test',
					title: title.value,
					knownFailing: false,
					todo: true,
				});
			} else {
				if (typeof implementation !== 'function') {
					throw new TypeError('Expected an implementation. Use `test.todo()` for tests without an implementation.');
				}

				if (title.isSet && !title.isValid) {

View on GitHub (pinned to bbfd946322)

Solutions

  1. Rename one of the duplicate tests so every test title in the file is unique
  2. If tests should share a scenario, use test.each-style parameterization with distinct interpolated titles
  3. If a copy-pasted test is unintended, delete the duplicate
  4. If the title is built dynamically, log/print the generated titles to find the collision

Example fix

// before
test('fetches user', async t => { ... });
test('fetches user', async t => { ... });

// after
test('fetches user by id', async t => { ... });
test('fetches user by email', async t => { ... });
Defensive patterns

Strategy: validation

Validate before calling

function assertUniqueTitles(tests) {
	const seen = new Set();
	for (const {title} of tests) {
		if (seen.has(title)) throw new Error(`Duplicate test title: ${title}`);
		seen.add(title);
	}
}
// call it over your declared/generated test definitions before running

Type guard

function hasUniqueTitles(titles) {
	return new Set(titles).size === titles.length;
}

Try / catch

try {
	runner.declareTests(tests);
} catch (err) {
	if (err.message.startsWith('Duplicate test title:')) {
		console.error(`Fix duplicate title: ${err.message}`);
	}
	throw err;
}

Prevention

When it happens

Trigger: Calling test('name', t => {}) twice with the same title string, or a test.todo('name') sharing a title with another test or todo, where both calls happen before the runner starts (synchronously in the test file).

Common situations: Copy-pasting a test block and forgetting to change the title; generating tests in a loop with a static or duplicated title string; renaming a test via parameterization that collapses to identical titles; merging branches where two developers added a test with the same name.

Related errors


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