facebook/docusaurus · error · Error

Multiple docs sidebar items produce the same translation key

Error message

Multiple docs sidebar items produce the same translation key.
- ${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- ')}

To avoid translation key conflicts, use the ${logger.code('key')} attribute on the sidebar items above to uniquely identify them.

When using autogenerated sidebars, you can provide a unique translation key by adding:
- the ${logger.code('key')} attribute to category item metadata (${logger.code('_category_.json')} / ${logger.code('_category_.yml')})
- the ${logger.code('sidebar_key')} attribute to doc item metadata (front matter in ${logger.code('Category/index.mdx')})

What it means

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.

Source

Thrown at packages/docusaurus-plugin-content-docs/src/translations.ts:55

    return versionName;
  }
  // I don't like this "version-" prefix,
  // but it's for consistency with site/versioned_docs
  return `version-${versionName}`;
}

type TranslationMessageEntry = [string, TranslationMessage];

function ensureNoSidebarDuplicateEntries(
  translationEntries: TranslationMessageEntry[],
): void {
  const grouped = _.groupBy(translationEntries, (entry) => entry[0]);
  const duplicates = Object.entries(grouped).filter(
    (entry) => entry[1].length > 1,
  );

  if (duplicates.length > 0) {
    throw new Error(`Multiple docs sidebar items produce the same translation key.
- ${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- ')}

To avoid translation key conflicts, use the ${logger.code(
      'key',
    )} attribute on the sidebar items above to uniquely identify them.

View on GitHub (pinned to 3f483e80e3)

Solutions

  1. Add a unique `key` attribute to each colliding category in sidebars.js: {type:'category', label:'Overview', key:'overview-getting-started', items:[...]}.
  2. For autogenerated categories, set `key` in the folder's _category_.json (or _category_.yml).
  3. For duplicate docs across sidebars, add `sidebar_key` in the doc's front matter to give each occurrence a unique translation key.
  4. Rename one of the colliding labels so the default keys diverge.

Example fix

// before: two categories share label 'Overview' -> duplicate key
const sidebars = {
  tutorial: [
    {type: 'category', label: 'Overview', items: ['a']},
    {type: 'category', label: 'Overview', items: ['b']},
  ],
};

// after: unique explicit key per category
const sidebars = {
  tutorial: [
    {type: 'category', label: 'Overview', key: 'overview-intro', items: ['a']},
    {type: 'category', label: 'Overview', key: 'overview-advanced', items: ['b']},
  ],
};
Defensive patterns

Strategy: validation

Validate before calling

// Detect duplicate translation keys before write-translations runs.
function collectKeys(items, sidebarName, acc = []) {
  for (const item of items) {
    if (item.type === 'category') {
      const k = item.key ?? item.label;
      acc.push(`sidebar.${sidebarName}.category.${k}`);
      if (item.items) collectKeys(item.items, sidebarName, acc);
    } else if (item.type === 'doc') {
      const k = item.sidebar_key ?? item.id;
      acc.push(`sidebar.${sidebarName}.doc.${k}`);
    }
  }
  return acc;
}
function findDuplicateTranslationKeys(sidebars) {
  const all = Object.entries(sidebars).flatMap(([n, s]) => collectKeys(s, n));
  const counts = {};
  all.forEach((k) => (counts[k] = (counts[k] || 0) + 1));
  return Object.entries(counts).filter(([, c]) => c > 1).map(([k]) => k);
}

Type guard

function categoryHasUniqueKey(cat, seenKeys) {
  const k = cat.key ?? cat.label;
  if (seenKeys.has(k)) return false;
  seenKeys.add(k);
  return true;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12). Data as JSON: /api/errors/30678026c9238375. Report an issue: GitHub.