{"record":{"id":"516cddbb5ece0b87","repo":"facebook/docusaurus","slug":"heading-ids-can-either-be-overwritten-or-migrated","errorCode":null,"errorMessage":"Heading ids can either be overwritten or migrated, not both at the same time","messagePattern":"Heading ids can either be overwritten or migrated, not both at the same time","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/docusaurus-utils/src/markdownHeadingIdUtils.ts","lineNumber":149,"sourceCode":" * Takes Markdown content, returns new content with heading IDs written.\n * Respects existing IDs (unless `overwrite=true`) and never generates colliding\n * IDs (through the slugger).\n */\nexport function writeMarkdownHeadingId(\n  content: string,\n  options: WriteHeadingIDOptions = {},\n): string {\n  const {\n    syntax = 'classic', // Maybe we'll want to change this default later?\n    overwrite = false,\n    migrate = false,\n    maintainCase = false,\n  } = options;\n\n  // For now, we have 2 booleans (retro compatible)\n  // but it could be useful to have a \"mode\" enum instead?\n  if (overwrite && migrate) {\n    throw new Error(\n      'Heading ids can either be overwritten or migrated, not both at the same time',\n    );\n  }\n\n  const lines = content.split('\\n');\n  const slugger = createSlugger();\n\n  // Parse heading ID trying both syntaxes (classic first, then mdx-comment)\n  function parseHeadingIdAnySyntax(heading: string) {\n    const classic = parseMarkdownHeadingId(heading, 'classic');\n    if (classic.id) {\n      return classic;\n    }\n    return parseMarkdownHeadingId(heading, 'mdx-comment');\n  }\n\n  // If we can't overwrite existing slugs, make sure other headings don't\n  // generate colliding slugs by first marking these slugs as occupied","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/facebook/docusaurus/blob/3f483e80e326cc646b54b83d564b3f0c4881b9a6/packages/docusaurus-utils/src/markdownHeadingIdUtils.ts#L131-L167","documentation":"Thrown by writeMarkdownHeadingId() when its options object has both overwrite: true and migrate: true. These two modes are mutually exclusive: overwrite regenerates heading IDs from the heading text (discarding any existing ID), while migrate rewrites existing IDs into the target syntax (preserving their value). Permitting both would be ambiguous, so the function rejects the combination up front.","triggerScenarios":"Invoking writeMarkdownHeadingId(content, { overwrite: true, migrate: true }) — most commonly via the `docusaurus write-heading-ids` CLI with both flags passed, or programmatically when wiring the function into a custom processor.","commonSituations":"Running `docusaurus write-heading-ids --overwrite --migrate` with both flags. A custom script that merges user options onto defaults where both booleans default to true. Confusion about the difference between the two modes leads to passing both 'to be safe'.","solutions":["Decide which behavior you want: pass --overwrite to regenerate IDs from heading text, or --migrate to preserve existing IDs and only change their syntax — never both.","If calling the API directly, set exactly one of { overwrite, migrate } to true (or neither for the default preserve-and-fill behavior).","Re-run the CLI or your script with a single mode flag.","If you genuinely need both effects (rewrite then change syntax), run the command twice sequentially: first overwrite, then migrate."],"exampleFix":"// before\nwriteMarkdownHeadingId(content, { overwrite: true, migrate: true });\n\n// after — pick one mode\nwriteMarkdownHeadingId(content, { overwrite: true });\n// or\nwriteMarkdownHeadingId(content, { migrate: true });","handlingStrategy":"validation","validationCode":"function isValidHeadingIdOptions(opts: { overwrite?: boolean; migrate?: boolean }): boolean {\n  return !(opts.overwrite && opts.migrate);\n}\n\nif (!isValidHeadingIdOptions(options)) {\n  throw new Error('Choose overwrite OR migrate, not both.');\n}","typeGuard":"function isSingleHeadingMode(opts: { overwrite?: boolean; migrate?: boolean }): boolean {\n  return !(opts.overwrite === true && opts.migrate === true);\n}","tryCatchPattern":"try {\n  writeMarkdownHeadingId(content, options);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('overwritten or migrated')) {\n    // pick one mode and retry\n  }\n  throw err;\n}","preventionTips":["Pass at most one of overwrite / migrate when invoking writeMarkdownHeadingId or the write-heading-ids CLI.","If you expose these options in a UI, make them mutually exclusive radio buttons.","Run the CLI twice (overwrite then migrate) if you genuinely need both effects sequentially."],"tags":["markdown","heading-ids","cli","validation","options"],"backgroundTag":null,"analyzedSha":"3f483e80e326cc646b54b83d564b3f0c4881b9a6","analyzedAt":"2026-08-12T13:25:04.382Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}