vectordotdev/vector · error

invalid fragment contents for

Error message

invalid fragment contents for '{filename}': scaffolder placeholder line still present ({bad:?}). Replace it with real content.

What it means

A line in the fragment body still starts with the literal `TODO ` at column 0, indicating an unfilled scaffolder placeholder. Templates deliberately mark template lines this way so the checker can reject incomplete fragments.

Solutions

  1. Find the line starting with `TODO ` and replace it with real content.
  2. Rephrase legitimate notes so they don't begin with `TODO ` at column 0 (e.g. indent or reword).
  3. Use the error's reported line ({bad:?}) to locate the exact offending text.

Example fix

// before
TODO describe the breaking change.
// after
Removed the `foo` option; migrate to `bar` before upgrading.
Defensive patterns

Strategy: validation

Validate before calling

let content = std::fs::read_to_string(path)?;
if let Some(bad) = content.lines().find(|l| l.starts_with("TODO ")) {
    panic!("unfilled scaffold placeholder: {bad:?}");
}

Prevention

When it happens

Trigger: Running `vdev check changelog-fragments` when any line of the fragment content begins with `TODO ` (the checker's heuristic for unfilled scaffold text).

Common situations: Committing a scaffolded fragment after filling only some sections; leaving a 'TODO describe the migration path' style line in a breaking fragment; writing genuine notes as a TODO line.

Related errors


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

Appendix: source

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

            "invalid fragment contents for '{filename}': author names should not be prefixed with '@'."
        );
    }
    if names.contains(',') {
        bail!(
            "invalid fragment contents for '{filename}': authors should be space delimited, not comma delimited."
        );
    }
    if names.split_whitespace().any(|n| n == TODO_HANDLE) {
        bail!(
            "invalid fragment contents for '{filename}': the scaffolder placeholder '{TODO_HANDLE}' must be replaced with a real GitHub handle."
        );
    }

    // Reject any scaffolded body placeholder that the author forgot to fill in.
    // All templates start their placeholder lines with a literal `TODO ` at column 0,
    // which is rare in real fragment text.
    if let Some(bad) = content.lines().find(|l| l.starts_with("TODO ")) {
        bail!(
            "invalid fragment contents for '{filename}': scaffolder placeholder line still present ({bad:?}). Replace it with real content."
        );
    }

    if fragment_type.breaking {
        validate_breaking_fragment(&content, filename)?;
    }

    Ok(())
}

/// Schema for `*.breaking.md`:
///
/// ```text
/// # <Title> [{#optional-anchor}]
///
/// ## Summary
///

View on GitHub (pinned to bdb87aeaa4)