vectordotdev/vector · error

invalid breaking fragment

Error message

invalid breaking fragment '{filename}': title still contains the scaffolder placeholder 'TODO'.

What it means

`vdev check changelog-fragments` rejects a breaking fragment whose title still contains the literal placeholder 'TODO' left by the fragment scaffolder. This catches fragments created from the template but never actually filled in.

Solutions

  1. Replace the TODO placeholder in the title with a real description of the breaking change.
  2. Re-run `make check-changelog-fragments` locally before pushing.

Example fix

// before
### TODO
// after
### "`http` source": removed deprecated `headers` config option
Defensive patterns

Strategy: validation

Validate before calling

let title = /* parsed title */;
if title.contains("TODO") { panic!("fill in the TODO before committing the fragment"); }

Type guard

fn title_filled(title: &str) -> bool { !title.is_empty() && !title.contains("TODO") }

Prevention

When it happens

Trigger: A breaking fragment file was generated from the scaffold template and committed with the title still containing 'TODO', e.g. `TODO: describe the change`.

Common situations: Contributor scaffolds a fragment early, forgets to replace the TODO before opening a PR; CI then fails the changelog-fragments check.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

/// <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)]
mod tests {
    use super::*;
    use indoc::{formatdoc, indoc};

View on GitHub (pinned to bdb87aeaa4)