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
- Rename one of the duplicate tests so every test title in the file is unique
- If tests should share a scenario, use test.each-style parameterization with distinct interpolated titles
- If a copy-pasted test is unintended, delete the duplicate
- 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
- Never copy-paste a test block without renaming its title
- When generating tests in loops, interpolate the loop variable into the title
- Add a CI lint rule or helper that asserts unique titles across generated tests
- Keep todo titles unique relative to regular test titles too
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
- Expected an implementation. Use `test.todo()` for tests with
- Test & hook titles must be strings
- Tests must have a title
- Duplicate test title: ${attemptTitle}
- The `any` property of the second argument to `${assertion}`
AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02).
Data as JSON: /api/errors/06ccadc0990e3fcc.
Report an issue: GitHub.