vectordotdev/vector · error

invalid fragment filename

Error message

invalid fragment filename '{filename}': extension must be markdown (.md).

What it means

Fired by validate_filename when a changelog fragment file's extension is not '.md'. The checker splits the filename on '.' and requires exactly three parts '<unique_name>.<fragment_type>.md'; a file with a different extension (e.g. 'foo.breaking.txt' or editor backups) fails this shape check and is rejected as an invalid fragment filename.

Solutions

  1. Rename the file so it ends in `.md`.
  2. Move non-Markdown notes out of the changelog.d directory.
  3. Delete leftover editor backup files from changelog.d/.

Example fix

// before
changelog.d/jdoe.new-feature.markdown
// after
changelog.d/jdoe.new-feature.md
Defensive patterns

Strategy: validation

Validate before calling

let name = "jdoe.new-feature.markdown";
assert_eq!(name.split('.').last().unwrap(), "md", "fragment must end in .md");

Prevention

When it happens

Trigger: Running `vdev check changelog-fragments` with files like `jdoe.new-feature.mdx`, `jdoe.new-feature.markdown`, or `jdoe.new-feature.md.orig` (parts.len()==3 but parts[2] != "md").

Common situations: Authoring in MDX; saving with a text editor that appends an extension; backup tools appending suffixes like `.orig` in changelog.d/.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

    let parts: Vec<&str> = filename.split('.').collect();
    if parts.len() != 3 {
        bail!(
            "invalid fragment filename '{filename}': expected '<unique_name>.<fragment_type>.md'"
        );
    }
    let fragment_type = parts[1];
    let Some(known) = FRAGMENT_TYPES.iter().find(|t| t.name == fragment_type) else {
        bail!(
            "invalid fragment filename '{filename}': fragment type must be one of ({}).",
            FRAGMENT_TYPES
                .iter()
                .map(|t| t.name)
                .collect::<Vec<_>>()
                .join("|")
        );
    };
    if parts[2] != "md" {
        bail!("invalid fragment filename '{filename}': extension must be markdown (.md).");
    }
    Ok(known)
}

fn validate_contents(
    path: &std::path::Path,
    filename: &str,
    fragment_type: &FragmentType,
) -> Result<()> {
    let content = std::fs::read_to_string(path)?;
    // Match generate_cue.rs, which reads `lines().last()` verbatim: the authors
    // line must be the last line, no trailing blank lines allowed.
    let last_line = content.lines().last().unwrap_or("");

    let Some(names) = last_line.strip_prefix("authors: ") else {
        bail!(
            "invalid fragment contents for '{filename}': last line must be 'authors: <name> [<name> ...]' (no trailing blank lines)."
        );

View on GitHub (pinned to bdb87aeaa4)