{"record":{"id":"8a643fec6e12f739","repo":"vectordotdev/vector","slug":"invalid-breaking-fragment-filename-anchor-must-be-a","errorCode":null,"errorMessage":"invalid breaking fragment '{filename}': anchor must be a lowercase kebab-case slug (a-z, 0-9, hyphens); got '{anchor}'.","messagePattern":"invalid breaking fragment '(.+?)': anchor must be a lowercase kebab-case slug \\(a-z, 0-9, hyphens\\); got '(.+?)'\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vdev/src/commands/check/changelog_fragments.rs","lineNumber":277,"sourceCode":"    let body_before_authors = content\n        .rsplit_once(\"\\nauthors: \")\n        .map_or(content, |(before, _)| before);\n\n    let sections = parse_breaking_sections(body_before_authors)\n        .map_err(|e| anyhow::anyhow!(\"invalid breaking fragment '{filename}': {e}\"))?;\n\n    if sections.title.is_empty() {\n        bail!(\"invalid breaking fragment '{filename}': title must not be empty.\");\n    }\n    if sections.title.contains(\"TODO\") {\n        bail!(\n            \"invalid breaking fragment '{filename}': title still contains the scaffolder placeholder 'TODO'.\"\n        );\n    }\n    if let Some(anchor) = sections.anchor.as_deref()\n        && !is_valid_anchor(anchor)\n    {\n        bail!(\n            \"invalid breaking fragment '{filename}': anchor must be a lowercase kebab-case slug (a-z, 0-9, hyphens); got '{anchor}'.\"\n        );\n    }\n\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use indoc::{formatdoc, indoc};\n\n    /// Build a full breaking-fragment file body from the given title line and section content.\n    fn wrap(title_line: &str, summary: &str, migration: &str) -> String {\n        formatdoc! {\"\n            {title_line}\n\n            ## Summary","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/vdev/src/commands/check/changelog_fragments.rs#L259-L295","documentation":"`vdev check changelog-fragments` rejects a breaking fragment whose optional `anchor` is not a lowercase kebab-case slug (only a-z, 0-9 and hyphens). The validation is done by `is_valid_anchor` and the error echoes the offending anchor text.","triggerScenarios":"A breaking fragment file contains an anchor containing uppercase letters, spaces, underscores, or other characters outside `[a-z0-9-]`.","commonSituations":"Author writes `anchor: My_Change` or uses spaces instead of hyphens when giving the fragment a stable anchor for docs links.","solutions":["Rewrite the anchor as lowercase kebab-case, e.g. `my-change-1234`.","Remove the anchor entirely if it is not needed (anchors are optional).","Re-run `make check-changelog-fragments`."],"exampleFix":"# before\nanchor: My_Change\n# after\nanchor: my-change","handlingStrategy":"validation","validationCode":"let anchor = \"my-change\";\nassert!(anchor.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-'), \"anchor must be kebab-case\");","typeGuard":"fn is_kebab(s: &str) -> bool { !s.is_empty() && s.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-') }","tryCatchPattern":null,"preventionTips":["Use lowercase-with-hyphens whenever adding an anchor.","Avoid underscores, spaces, and uppercase in anchors.","Derive the anchor from the title with a slugify helper."],"tags":["changelog","validation","naming","ci"],"backgroundTag":"invalid-identifier-format","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}