vercel/next.js · error
Specified i18n.locales contains the following duplicate loca
Error message
Specified i18n.locales contains the following duplicate locales:
${[...duplicateLocales].join(', ')}
Each locale should be listed only once.
See more info here: https://nextjs.org/docs/messages/invalid-i18n-config What it means
Thrown at config.ts:1330 when `i18n.locales` contains case-insensitive duplicates. The code lowercases each locale and adds it to a `normalizedLocales` set; if a lowercased form is already present, the original-casing value is recorded in `duplicateLocales`. The error lists the duplicates and requires each locale to appear once.
Source
Thrown at packages/next/src/server/config.ts:1331
if (!i18n.locales.includes(i18n.defaultLocale)) {
throw new Error(
`Specified i18n.defaultLocale should be included in i18n.locales.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`
)
}
const normalizedLocales = new Set()
const duplicateLocales = new Set()
i18n.locales.forEach((locale) => {
const localeLower = locale.toLowerCase()
if (normalizedLocales.has(localeLower)) {
duplicateLocales.add(locale)
}
normalizedLocales.add(localeLower)
})
if (duplicateLocales.size > 0) {
throw new Error(
`Specified i18n.locales contains the following duplicate locales:\n` +
`${[...duplicateLocales].join(', ')}\n` +
`Each locale should be listed only once.\n` +
`See more info here: https://nextjs.org/docs/messages/invalid-i18n-config`
)
}
// make sure default Locale is at the front
i18n.locales = [
i18n.defaultLocale,
...i18n.locales.filter((locale) => locale !== i18n.defaultLocale),
]
const localeDetectionType = typeof i18n.localeDetection
if (
localeDetectionType !== 'boolean' &&
localeDetectionType !== 'undefined'View on GitHub (pinned to 0ae8c72462)
Solutions
- Remove the duplicate locale entries so each appears exactly once.
- If duplicates arise from case differences, standardize on a single canonical casing.
- Dedupe programmatically when building the list: `locales: [...new Set(allLocales.map((l) => l))]` (and normalize case first if needed).
Example fix
// before
i18n: { locales: ['en-US', 'EN-US', 'fr'], defaultLocale: 'en-US' }
// after
i18n: { locales: ['en-US', 'fr'], defaultLocale: 'en-US' } Defensive patterns
Strategy: validation
Validate before calling
const lower = i18n.locales.map((l: string) => l.toLowerCase());
if (new Set(lower).size !== lower.length) throw new Error('duplicate (case-insensitive) locales'); Type guard
function noCaseInsensitiveDuplicates(locales: string[]): boolean {
const lower = locales.map((l) => l.toLowerCase());
return new Set(lower).size === lower.length;
} Prevention
- Normalize locale casing upstream (e.g. always canonical case).
- Dedupe with `Array.from(new Set(locales.map((l) => l)))` before exporting.
When it happens
Trigger: `locales: ['en-US', 'EN-US']`; `locales: ['fr', 'FR', 'Fr']`; `locales: ['pt-BR', 'pt-br']`. Mixed casing is treated as the same locale.
Common situations: Merging locale lists from multiple teams/modules without deduplication; CMS-driven locale config that injects variants; copy-paste duplication.
Related errors
- Invalid i18n.domains values: ${invalidDomainItems.map((item:
- Specified i18n.locales contains invalid values (${invalidLoc
- Specified i18n.defaultLocale should be included in i18n.loca
- Specified "i18n" cannot be used with "output: export". See m
- Specified basePath has to start with a /, found "${result.ba
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/67728b524413e695.
Report an issue: GitHub.