avajs/ava · error · Error
Unexpected duplicate extensions in options: ’${[...duplicate
Error message
Unexpected duplicate extensions in options: ’${[...duplicates].join('’, ’')}’. What it means
AVA builds the final extension list from your `extensions` option plus extensions contributed by providers (like @ava/typescript). If the same extension ends up registered more than once, resolveExtensions throws to keep the extension pattern unambiguous.
Source
Thrown at lib/extensions.js:29
seen.add(ext);
}
}
};
if (configuredExtensions !== undefined) {
if (!Array.isArray(configuredExtensions)) {
throw new TypeError('The extensions option must be an array');
}
combine(configuredExtensions);
}
for (const {main} of providers) {
combine(main.extensions);
}
if (duplicates.size > 0) {
throw new Error(`Unexpected duplicate extensions in options: ’${[...duplicates].join('’, ’')}’.`);
}
// Unless the default was used by providers, as long as the extensions aren't explicitly set, set the default.
if (configuredExtensions === undefined) {
if (!seen.has('mjs')) {
seen.add('mjs');
}
if (!seen.has('js')) {
seen.add('js');
}
}
return [...seen];
}
View on GitHub (pinned to bbfd946322)
Solutions
- Remove duplicate entries from the `extensions` array.
- If @ava/typescript is installed, drop 'ts' from your list and let the provider supply it.
- Deduplicate programmatically when building config: `[...new Set(extensions)]`.
- Check config merge logic (CLI flags + config file) for accidental concatenation.
Example fix
// before
export default {extensions: ['js', 'mjs', 'mjs']};
// after
export default {extensions: ['js', 'mjs']}; Defensive patterns
Strategy: validation
Validate before calling
const exts = config.extensions ?? [];
const dups = exts.filter((e, i) => exts.indexOf(e) !== i);
if (dups.length) throw new Error(`Duplicate extensions: ${dups}`); Type guard
const hasNoDuplicateExtensions = v => !Array.isArray(v) || new Set(v).size === v.length;
Try / catch
try {
await run();
} catch (err) {
if (err.message.startsWith('Unexpected duplicate extensions')) {
console.error('Deduplicate the extensions option; provider extensions (e.g. @ava/typescript) count too');
process.exitCode = 1;
} else throw err;
} Prevention
- Build the list via [...new Set(extensions)] when merging config layers.
- Do not manually add 'ts' when @ava/typescript is installed.
- Keep a single source of truth for extensions instead of merging multiple configs.
- Review config concatenation helpers for accidental joins.
When it happens
Trigger: Listing the same extension twice, e.g. `extensions: ['js', 'mjs', 'js']`, or combining your `extensions` config with a provider (e.g. @ava/typescript) that already contributes 'ts' and re-adding 'ts' yourself.
Common situations: Merging config objects where both base config and override add the same extension; adding 'ts' manually while @ava/typescript is installed; accumulating extensions across config layers without deduplication.
Related errors
- The ’environmentVariables’ configuration must be an object c
- The extensions option must be an array
- The ’files’ configuration must be an array containing glob p
- The ’watchMode.ignoreChanges’ configuration must be an array
- ${fileForErrorMessage} must export a plain object or factory
AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02).
Data as JSON: /api/errors/c5443828bbc1986f.
Report an issue: GitHub.