{"record":{"id":"30678026c9238375","repo":"facebook/docusaurus","slug":"multiple-docs-sidebar-items-produce-the-same-trans","errorCode":null,"errorMessage":"Multiple docs sidebar items produce the same translation key.\n- ${duplicates.map(([translationKey, entries]) => { return `${logger.code(translationKey)}: ${logger.num(entries.length)} duplicates found:\\n  - ${entries.map((duplicate) => { const desc = duplicate[1].description; return `${logger.name(duplicate[1].message)} ${desc ? `(${logger.subdue(desc)})` : ''}`; }).join('\\n  - ')}`; }).join('\\n\\n- ')}\n\nTo avoid translation key conflicts, use the ${logger.code('key')} attribute on the sidebar items above to uniquely identify them.\n\nWhen using autogenerated sidebars, you can provide a unique translation key by adding:\n- the ${logger.code('key')} attribute to category item metadata (${logger.code('_category_.json')} / ${logger.code('_category_.yml')})\n- the ${logger.code('sidebar_key')} attribute to doc item metadata (front matter in ${logger.code('Category/index.mdx')})","messagePattern":"Multiple docs sidebar items produce the same translation key\\.\n- \\$\\{duplicates\\.map\\(\\(\\[translationKey, entries\\]\\) => \\{ return `\\$\\{logger\\.code\\(translationKey\\)\\}: \\$\\{logger\\.num\\(entries\\.length\\)\\} duplicates found:\\\\n  - \\$\\{entries\\.map\\(\\(duplicate\\) => \\{ const desc = duplicate\\[1\\]\\.description; return `\\$\\{logger\\.name\\(duplicate\\[1\\]\\.message\\)\\} \\$\\{desc \\? `\\(\\$\\{logger\\.subdue\\(desc\\)\\}\\)` : ''\\}`; \\}\\)\\.join\\('\\\\n  - '\\)\\}`; \\}\\)\\.join\\('\\\\n\\\\n- '\\)\\}\n\nTo avoid translation key conflicts, use the \\$\\{logger\\.code\\('key'\\)\\} attribute on the sidebar items above to uniquely identify them\\.\n\nWhen using autogenerated sidebars, you can provide a unique translation key by adding:\n- the \\$\\{logger\\.code\\('key'\\)\\} attribute to category item metadata \\(\\$\\{logger\\.code\\('_category_\\.json'\\)\\} / \\$\\{logger\\.code\\('_category_\\.yml'\\)\\}\\)\n- the \\$\\{logger\\.code\\('sidebar_key'\\)\\} attribute to doc item metadata \\(front matter in \\$\\{logger\\.code\\('Category/index\\.mdx'\\)\\}\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/docusaurus-plugin-content-docs/src/translations.ts","lineNumber":55,"sourceCode":"    return versionName;\n  }\n  // I don't like this \"version-\" prefix,\n  // but it's for consistency with site/versioned_docs\n  return `version-${versionName}`;\n}\n\ntype TranslationMessageEntry = [string, TranslationMessage];\n\nfunction ensureNoSidebarDuplicateEntries(\n  translationEntries: TranslationMessageEntry[],\n): void {\n  const grouped = _.groupBy(translationEntries, (entry) => entry[0]);\n  const duplicates = Object.entries(grouped).filter(\n    (entry) => entry[1].length > 1,\n  );\n\n  if (duplicates.length > 0) {\n    throw new Error(`Multiple docs sidebar items produce the same translation key.\n- ${duplicates\n      .map(([translationKey, entries]) => {\n        return `${logger.code(translationKey)}: ${logger.num(\n          entries.length,\n        )} duplicates found:\\n  - ${entries\n          .map((duplicate) => {\n            const desc = duplicate[1].description;\n            return `${logger.name(duplicate[1].message)} ${\n              desc ? `(${logger.subdue(desc)})` : ''\n            }`;\n          })\n          .join('\\n  - ')}`;\n      })\n      .join('\\n\\n- ')}\n\nTo avoid translation key conflicts, use the ${logger.code(\n      'key',\n    )} attribute on the sidebar items above to uniquely identify them.","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/facebook/docusaurus/blob/3f483e80e326cc646b54b83d564b3f0c4881b9a6/packages/docusaurus-plugin-content-docs/src/translations.ts#L37-L73","documentation":"Thrown by ensureNoSidebarDuplicateEntries() while the plugin generates the translation file (writeTranslations). It groups translation entries by their translation key (e.g. `sidebar.<sidebarName>.category.<key>`); if two or more entries share a key, translation systems cannot disambiguate them, so the build aborts and the message names each conflicting key plus the entries that collide. The fix is to give sidebar items an explicit, unique key.","triggerScenarios":"Two categories in the same sidebar share the same label (and therefore the same default key); the same doc appears in multiple sidebars without a unique sidebar_key; autogenerated categories whose folders have identical names produce duplicate category keys; a doc and a category share a label.","commonSituations":"Running `docusaurus write-translations` after adding sidebars with duplicate labels; i18n setup on a site that reuses common labels like 'Overview' or 'Introduction' across nested categories; refactoring that duplicated category folders.","solutions":["Add a unique `key` attribute to each colliding category in sidebars.js: {type:'category', label:'Overview', key:'overview-getting-started', items:[...]}.","For autogenerated categories, set `key` in the folder's _category_.json (or _category_.yml).","For duplicate docs across sidebars, add `sidebar_key` in the doc's front matter to give each occurrence a unique translation key.","Rename one of the colliding labels so the default keys diverge."],"exampleFix":"// before: two categories share label 'Overview' -> duplicate key\nconst sidebars = {\n  tutorial: [\n    {type: 'category', label: 'Overview', items: ['a']},\n    {type: 'category', label: 'Overview', items: ['b']},\n  ],\n};\n\n// after: unique explicit key per category\nconst sidebars = {\n  tutorial: [\n    {type: 'category', label: 'Overview', key: 'overview-intro', items: ['a']},\n    {type: 'category', label: 'Overview', key: 'overview-advanced', items: ['b']},\n  ],\n};","handlingStrategy":"validation","validationCode":"// Detect duplicate translation keys before write-translations runs.\nfunction collectKeys(items, sidebarName, acc = []) {\n  for (const item of items) {\n    if (item.type === 'category') {\n      const k = item.key ?? item.label;\n      acc.push(`sidebar.${sidebarName}.category.${k}`);\n      if (item.items) collectKeys(item.items, sidebarName, acc);\n    } else if (item.type === 'doc') {\n      const k = item.sidebar_key ?? item.id;\n      acc.push(`sidebar.${sidebarName}.doc.${k}`);\n    }\n  }\n  return acc;\n}\nfunction findDuplicateTranslationKeys(sidebars) {\n  const all = Object.entries(sidebars).flatMap(([n, s]) => collectKeys(s, n));\n  const counts = {};\n  all.forEach((k) => (counts[k] = (counts[k] || 0) + 1));\n  return Object.entries(counts).filter(([, c]) => c > 1).map(([k]) => k);\n}","typeGuard":"function categoryHasUniqueKey(cat, seenKeys) {\n  const k = cat.key ?? cat.label;\n  if (seenKeys.has(k)) return false;\n  seenKeys.add(k);\n  return true;\n}","tryCatchPattern":null,"preventionTips":["Give every category an explicit unique key in sidebars.js or _category_.json.","For docs reused across sidebars, set a unique sidebar_key in front matter.","Run `docusaurus write-translations` locally before pushing to catch duplicates early."],"tags":["docs","sidebar","i18n","translations","configuration"],"backgroundTag":null,"analyzedSha":"3f483e80e326cc646b54b83d564b3f0c4881b9a6","analyzedAt":"2026-08-12T13:25:04.382Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}