{"record":{"id":"0eb43e957bb32175","repo":"vectordotdev/vector","slug":"duplicate-upgrade-guide-anchor-shared-by-breaking-fragments","errorCode":null,"errorMessage":"duplicate upgrade-guide anchor '#{}' shared by breaking fragments '{other}' and '{}'. Override one with `{{#unique-slug}}`.","messagePattern":"duplicate upgrade-guide anchor '#(.+?)' shared by breaking fragments '(.+?)' and '(.+?)'\\. Override one with `(.+?)\\}`\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vdev/src/commands/release/generate_cue.rs","lineNumber":751,"sourceCode":"    let version_slug = format!(\"{}-{}-{}\", version.major, version.minor, version.patch);\n    format!(\"{date}-{version_slug}-upgrade-guide.md\")\n}\n\n/// Fail the release if any breaking fragment produced an invalid, empty, or duplicate\n/// anchor. Uses the same anchor rules as `vdev check changelog-fragments` (shared through\n/// `commands::changelog::is_valid_anchor`) so a fragment that passes CI can't fail here.\nfn validate_breaking_anchors(breaking: &[&BreakingDetails]) -> Result<()> {\n    let mut seen = std::collections::HashMap::<&str, &str>::new();\n    for b in breaking {\n        if !crate::commands::changelog::is_valid_anchor(&b.anchor) {\n            bail!(\n                \"breaking fragment '{}' has an invalid anchor '{}'. Add `{{#some-valid-slug}}` after the title.\",\n                b.title,\n                b.anchor,\n            );\n        }\n        if let Some(other) = seen.insert(b.anchor.as_str(), b.title.as_str()) {\n            bail!(\n                \"duplicate upgrade-guide anchor '#{}' shared by breaking fragments '{other}' and '{}'. Override one with `{{#unique-slug}}`.\",\n                b.anchor,\n                b.title,\n            );\n        }\n    }\n    Ok(())\n}\n\n/// Write `content` to `path` via a `.tmp` sibling then atomic rename. Prevents leaving a\n/// partial output behind if the process is killed mid-write.\nfn atomic_write(path: &Path, content: &str) -> Result<()> {\n    let tmp = path.with_extension(format!(\n        \"{}.tmp\",\n        path.extension().and_then(|e| e.to_str()).unwrap_or(\"\")\n    ));\n    fs::write(&tmp, content).with_context(|| format!(\"Failed to write {}\", tmp.display()))?;\n    fs::rename(&tmp, path)","sourceCodeStart":733,"sourceCodeEnd":769,"githubUrl":"https://github.com/vectordotdev/vector/blob/0d4ab78a4f0d9c9e5d03a50108a2ae4d2f4b2460/vdev/src/commands/release/generate_cue.rs#L733-L769","documentation":"During breaking-fragment validation, anchors must be unique across the release's upgrade guide; `validate_breaking_anchors` keeps a HashMap of anchor-to-title and bails when two fragments map to the same anchor. Duplicate anchors would produce ambiguous markdown links in the generated upgrade guide.","triggerScenarios":"Two or more breaking changelog fragments in changelog.d declare the same `{{#slug}}` anchor (or derive identical slugs from their titles), and `vdev release generate-cue` runs validate_breaking_anchors.","commonSituations":"Two PRs independently picked the same intuitive slug like `{{#breaking-change}}` or `{{#configuration}}`, or a fragment was copied from an earlier one without renaming its anchor.","solutions":["Identify the two conflicting fragment titles from the message.","Override one fragment's anchor with a unique slug, e.g. `{{#unique-slug}}` or a more descriptive name.","Run `vdev check changelog-fragments` to confirm anchors are valid and unique.","Re-run `vdev release generate-cue`."],"exampleFix":"// before: two fragments both use {{#configuration}}\n## new required config field {{#configuration}}\n// after\n## new required config field {{#new-required-config-field}}","handlingStrategy":"validation","validationCode":"// detect duplicate anchors across changelog.d before release\nconst anchors = fragments.map(f => f.anchor);\nconst dupes = anchors.filter((a, i) => anchors.indexOf(a) !== i);\nif (dupes.length) throw new Error(`duplicate anchors: ${dupes.join(\", \")}`);","typeGuard":null,"tryCatchPattern":"if let Err(e) = run() {\n    if e.to_string().contains(\"duplicate upgrade-guide anchor\") {\n        eprintln!(\"rename one fragment's {{#slug}} to a unique value and re-run\");\n    }\n}","preventionTips":["Derive anchors from the fragment filename/PR number to keep them unique.","Grep changelog.d for the intended slug before reusing it.","Include a duplicate-anchor check in CI alongside the fragment lint."],"tags":["changelog","validation","duplicate","anchor"],"backgroundTag":"conflicting-config-options","analyzedSha":"0d4ab78a4f0d9c9e5d03a50108a2ae4d2f4b2460","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}