{"record":{"id":"78f9a2a2740795bd","repo":"vercel/next.js","slug":"invalid-i18n-domains-values-invaliddomainitems","errorCode":null,"errorMessage":"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","messagePattern":"Invalid i18n\\.domains values:\n(.+?)\n\ndomains value must follow format (.+?)\\.\nSee more info here: https://nextjs\\.org/docs/messages/invalid-i18n-config","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/next/src/server/config.ts","lineNumber":1282,"sourceCode":"\n            for (const domainItem of i18n.domains || []) {\n              if (domainItem === item) continue\n              if (domainItem.locales && domainItem.locales.includes(locale)) {\n                console.warn(\n                  `Both ${item.domain} and ${domainItem.domain} configured the locale (${locale}) but only one can. Remove it from one i18n.domains config to continue`\n                )\n                hasInvalidLocale = true\n                break\n              }\n            }\n          }\n        }\n\n        return hasInvalidLocale\n      })\n\n      if (invalidDomainItems.length > 0) {\n        throw new Error(\n          `Invalid i18n.domains values:\\n${invalidDomainItems\n            .map((item: any) => JSON.stringify(item))\n            .join(\n              '\\n'\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`\n        )\n      }\n    }\n\n    if (!Array.isArray(i18n.locales)) {\n      throw new Error(\n        `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`\n      )\n    }\n\n    const invalidLocales = i18n.locales.filter(\n      (locale: any) => typeof locale !== 'string'\n    )","sourceCodeStart":1264,"sourceCodeEnd":1300,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/packages/next/src/server/config.ts#L1264-L1300","documentation":"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`.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\ni18n: { domains: [ { domain: 'https://example.fr', defaultLocale: 'fr' }, { domain: 'example.de', defaultLocale: 'fr' } ] }\n// after\ni18n: { domains: [ { domain: 'example.fr', defaultLocale: 'fr', locales: ['fr'] }, { domain: 'example.de', defaultLocale: 'de', locales: ['de'] } ] }","handlingStrategy":"validation","validationCode":"function validateDomains(domains, locales) {\n  const seenDefault = new Set();\n  const seenLocale = new Set();\n  for (const d of domains) {\n    if (!d || typeof d.domain !== 'string' || d.domain.includes(':') || !d.defaultLocale) throw new Error('bad domain entry');\n    if (seenDefault.has(d.defaultLocale)) throw new Error('duplicate defaultLocale across domains');\n    seenDefault.add(d.defaultLocale);\n    for (const l of d.locales ?? []) {\n      if (typeof l !== 'string') throw new Error('non-string locale in domain');\n      if (seenLocale.has(l)) throw new Error('locale in two domains');\n      seenLocale.add(l);\n    }\n  }\n}","typeGuard":"function isDomainEntry(x: any): x is { domain: string; defaultLocale: string; locales?: string[] } {\n  return (\n    x && typeof x === 'object' &&\n    typeof x.domain === 'string' && !x.domain.includes(':') &&\n    !!x.defaultLocale &&\n    (x.locales === undefined || (Array.isArray(x.locales) && x.locales.every((l: any) => typeof l === 'string')))\n  );\n}","tryCatchPattern":null,"preventionTips":["Never include protocol or port in `domain` values.","Ensure defaultLocale is unique across domain entries.","Ensure each locale string belongs to exactly one domain."],"tags":["config","i18n","validation"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}