{"record":{"id":"c5443828bbc1986f","repo":"avajs/ava","slug":"unexpected-duplicate-extensions-in-options","errorCode":null,"errorMessage":"Unexpected duplicate extensions in options: ’${[...duplicates].join('’, ’')}’.","messagePattern":"Unexpected duplicate extensions in options: ’(.+?)’\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/extensions.js","lineNumber":29,"sourceCode":"\t\t\t\tseen.add(ext);\n\t\t\t}\n\t\t}\n\t};\n\n\tif (configuredExtensions !== undefined) {\n\t\tif (!Array.isArray(configuredExtensions)) {\n\t\t\tthrow new TypeError('The extensions option must be an array');\n\t\t}\n\n\t\tcombine(configuredExtensions);\n\t}\n\n\tfor (const {main} of providers) {\n\t\tcombine(main.extensions);\n\t}\n\n\tif (duplicates.size > 0) {\n\t\tthrow new Error(`Unexpected duplicate extensions in options: ’${[...duplicates].join('’, ’')}’.`);\n\t}\n\n\t// Unless the default was used by providers, as long as the extensions aren't explicitly set, set the default.\n\tif (configuredExtensions === undefined) {\n\t\tif (!seen.has('mjs')) {\n\t\t\tseen.add('mjs');\n\t\t}\n\n\t\tif (!seen.has('js')) {\n\t\t\tseen.add('js');\n\t\t}\n\t}\n\n\treturn [...seen];\n}\n","sourceCodeStart":11,"sourceCodeEnd":45,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/extensions.js#L11-L45","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nexport default {extensions: ['js', 'mjs', 'mjs']};\n// after\nexport default {extensions: ['js', 'mjs']};","handlingStrategy":"validation","validationCode":"const exts = config.extensions ?? [];\nconst dups = exts.filter((e, i) => exts.indexOf(e) !== i);\nif (dups.length) throw new Error(`Duplicate extensions: ${dups}`);","typeGuard":"const hasNoDuplicateExtensions = v => !Array.isArray(v) || new Set(v).size === v.length;","tryCatchPattern":"try {\n  await run();\n} catch (err) {\n  if (err.message.startsWith('Unexpected duplicate extensions')) {\n    console.error('Deduplicate the extensions option; provider extensions (e.g. @ava/typescript) count too');\n    process.exitCode = 1;\n  } else throw err;\n}","preventionTips":["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."],"tags":["configuration","validation","duplicates"],"backgroundTag":"duplicate-config-value","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}