vectordotdev/vector · error

invalid breaking fragment

Error message

invalid breaking fragment '{filename}': title must not be empty.

What it means

`vdev check changelog-fragments` rejects a breaking-change changelog fragment whose title section is empty. The fragment is parsed by `parse_breaking_sections` and the check bails with an `anyhow` error naming the offending file. This enforces the rule that every breaking fragment must have a meaningful title.

Solutions

  1. Add a non-empty title to the fragment file (the section parsed as the title, e.g. the top heading).
  2. Verify the fragment follows the breaking-fragment template in changelog.d/README.md.
  3. Re-run the check: `make check-changelog-fragments`.

Example fix

# before (breaking/1234_fix.md)
## Breaking change


# after
## Breaking change
### "`kafka` sink": `librdkafka` bumped to X, config option `foo` removed
Defensive patterns

Strategy: validation

Validate before calling

let body = std::fs::read_to_string(path)?;
let title = body.lines().find(|l| l.starts_with("### ")).map(|l| l[4..].trim());
if title.map_or(true, |t| t.is_empty()) { return Err(format!("{path:?}: empty breaking-change title")); }

Type guard

fn has_title(content: &str) -> bool {
    content.lines().any(|l| l.starts_with("### ") && !l[4..].trim().is_empty())
}

Prevention

When it happens

Trigger: Running the changelog fragment check with a `breaking/` fragment file whose title line/section is empty or missing, so `sections.title.is_empty()` is true.

Common situations: A contributor created a fragment from the scaffold but deleted the title text without filling it in; an automated file rename left a stub file; an editor stripped the heading content.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/ceb72cfc02b4f439. Report an issue: GitHub.

Appendix: source

Thrown at vdev/src/commands/check/changelog_fragments.rs:267

///
/// ## Migration
///
/// <markdown — "Action needed" body for the upgrade guide, or "N/A">
///
/// authors: <name> [<name> ...]
/// ```
fn validate_breaking_fragment(content: &str, filename: &str) -> Result<()> {
    // Strip the trailing `authors:` line before parsing — it's not part of the markdown
    // structure and would otherwise land inside the Migration section.
    let body_before_authors = content
        .rsplit_once("\nauthors: ")
        .map_or(content, |(before, _)| before);

    let sections = parse_breaking_sections(body_before_authors)
        .map_err(|e| anyhow::anyhow!("invalid breaking fragment '{filename}': {e}"))?;

    if sections.title.is_empty() {
        bail!("invalid breaking fragment '{filename}': title must not be empty.");
    }
    if sections.title.contains("TODO") {
        bail!(
            "invalid breaking fragment '{filename}': title still contains the scaffolder placeholder 'TODO'."
        );
    }
    if let Some(anchor) = sections.anchor.as_deref()
        && !is_valid_anchor(anchor)
    {
        bail!(
            "invalid breaking fragment '{filename}': anchor must be a lowercase kebab-case slug (a-z, 0-9, hyphens); got '{anchor}'."
        );
    }

    Ok(())
}

#[cfg(test)]

View on GitHub (pinned to bdb87aeaa4)