vercel/next.js · error
Invalid i18n.domains values: ${invalidDomainItems.map((item:
Error message
Invalid i18n.domains values:
${invalidDomainItems.map((item: any) => JSON.stringify(item)).join('\n')}
domains value must follow format { domain: 'example.fr', defaultLocale: 'fr', locales: ['fr'] }.
See more info here: https://nextjs.org/docs/messages/invalid-i18n-config What it means
Thrown when one or more entries in `i18n.domains` fail structural validation (config.ts:1234-1289). An item is invalid if it is not an object, lacks `defaultLocale`, lacks a string `domain`, the domain contains a `:` (protocol/port), two domains share the same `defaultLocale`, a domain's `locales` contains a non-string, or the same locale appears in two domains. The error message lists the offending items via `JSON.stringify`.
Source
Thrown at packages/next/src/server/config.ts:1282
for (const domainItem of i18n.domains || []) {
if (domainItem === item) continue
if (domainItem.locales && domainItem.locales.includes(locale)) {
console.warn(
`Both ${item.domain} and ${domainItem.domain} configured the locale (${locale}) but only one can. Remove it from one i18n.domains config to continue`
)
hasInvalidLocale = true
break
}
}
}
}
return hasInvalidLocale
})
if (invalidDomainItems.length > 0) {
throw new Error(
`Invalid i18n.domains values:\n${invalidDomainItems
.map((item: any) => JSON.stringify(item))
.join(
'\n'
)}\n\ndomains value must follow format { domain: 'example.fr', defaultLocale: 'fr', locales: ['fr'] }.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`
)
}
}
if (!Array.isArray(i18n.locales)) {
throw new Error(
`Specified i18n.locales must be an array of locale strings e.g. ["en-US", "nl-NL"] received ${typeof i18n.locales}.\nSee more info here: https://nextjs.org/docs/messages/invalid-i18n-config`
)
}
const invalidLocales = i18n.locales.filter(
(locale: any) => typeof locale !== 'string'
)View on GitHub (pinned to 0ae8c72462)
Solutions
- Inspect the JSON-stringified offending items in the message and fix each reported field.
- Strip protocol and port from `domain` values: use `'example.fr'`, not `'https://example.fr:3000'`.
- Ensure each `defaultLocale` is unique across all domain entries.
- Ensure each locale string appears in only one domain's `locales` array.
- Verify every domain object has `domain` (string, no `:`), `defaultLocale`, and optionally `locales` (array of strings).
Example fix
// before
i18n: { domains: [ { domain: 'https://example.fr', defaultLocale: 'fr' }, { domain: 'example.de', defaultLocale: 'fr' } ] }
// after
i18n: { domains: [ { domain: 'example.fr', defaultLocale: 'fr', locales: ['fr'] }, { domain: 'example.de', defaultLocale: 'de', locales: ['de'] } ] } Defensive patterns
Strategy: validation
Validate before calling
function validateDomains(domains, locales) {
const seenDefault = new Set();
const seenLocale = new Set();
for (const d of domains) {
if (!d || typeof d.domain !== 'string' || d.domain.includes(':') || !d.defaultLocale) throw new Error('bad domain entry');
if (seenDefault.has(d.defaultLocale)) throw new Error('duplicate defaultLocale across domains');
seenDefault.add(d.defaultLocale);
for (const l of d.locales ?? []) {
if (typeof l !== 'string') throw new Error('non-string locale in domain');
if (seenLocale.has(l)) throw new Error('locale in two domains');
seenLocale.add(l);
}
}
} Type guard
function isDomainEntry(x: any): x is { domain: string; defaultLocale: string; locales?: string[] } {
return (
x && typeof x === 'object' &&
typeof x.domain === 'string' && !x.domain.includes(':') &&
!!x.defaultLocale &&
(x.locales === undefined || (Array.isArray(x.locales) && x.locales.every((l: any) => typeof l === 'string')))
);
} Prevention
- Never include protocol or port in `domain` values.
- Ensure defaultLocale is unique across domain entries.
- Ensure each locale string belongs to exactly one domain.
When it happens
Trigger: Domain entry missing `domain` or `defaultLocale`; setting `domain: 'https://example.fr:3000'` (contains `:`); two domain entries both declaring `defaultLocale: 'fr'`; `locales: [123]` inside a domain; a locale string listed under two different domains.
Common situations: Copying a domain URL with the protocol/port prefix; reusing the same default locale across regional domains by mistake; mixing locale arrays across domains during a migration; silent `console.warn` for duplicate locales that then escalate to a throw.
Related errors
- Specified i18n.locales contains invalid values (${invalidLoc
- Specified i18n.defaultLocale should be included in i18n.loca
- Specified i18n.locales contains the following duplicate 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/78f9a2a2740795bd.
Report an issue: GitHub.