vectordotdev/vector · error

Changelog fragment is invalid (filename must be . .md)

Error message

Changelog fragment {} is invalid (filename must be <name>.<type>.md)

What it means

Changelog fragment filenames must follow the strict `<name>.<type>.md` pattern. `parse_changelog_fragment` splits the file stem on '.' and requires exactly two parts; otherwise the fragment is rejected because its type cannot be determined.

Solutions

  1. Rename the fragment to exactly one dot: `<name>.<type>.md`, e.g. `my-fix.enhancement.md`.
  2. Remove non-fragment files (notes, backups, editor droppings) from `changelog.d/`.
  3. Check `changelog.d/README.md` for the valid fragment types and naming rules.

Example fix

// before
changelog.d/fix-0.45.md
// after
changelog.d/fix-0.45.bug.md   # or rename without inner dots, e.g. fix-0-45.bug.md
Defensive patterns

Strategy: validation

Validate before calling

name=$(basename "$f" .md); [[ "$name" == *.* && "$(echo "$name" | tr -cd '.' | wc -c)" -eq 1 ]] || echo "bad fragment name: $f"

Prevention

When it happens

Trigger: Placing a file in `changelog.d/` whose stem contains zero or more than one dot, e.g. `my-fix.md`, `my.fix.extra.md`, or `archive.tar.md`.

Common situations: Naming a fragment like a regular markdown note (`notes.md`); including a version number with dots in the name (`fix-0.45.md`); stray editor or backup files landing 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@0d4ab78a4f (2026-09-16). Data as JSON: /api/errors/d28444429143dd06. Report an issue: GitHub.

Appendix: source

Thrown at vdev/src/commands/release/generate_cue.rs:357

        .filter(|p| p.file_name().and_then(|n| n.to_str()) != Some("README.md"))
        .collect();
    paths.sort();
    for path in paths {
        let mut entry = parse_changelog_fragment(&path)?;
        entry.pr_numbers = lookup_pull_requests(repo_root, &path, pull_request_metadata)?;
        entries.push(entry);
    }
    Ok(entries)
}

fn parse_changelog_fragment(path: &Path) -> Result<ChangelogEntry> {
    let stem = path
        .file_stem()
        .and_then(|n| n.to_str())
        .ok_or_else(|| anyhow!("Bad fragment filename: {}", path.display()))?;
    let parts: Vec<&str> = stem.split('.').collect();
    if parts.len() != 2 {
        bail!(
            "Changelog fragment {} is invalid (filename must be <name>.<type>.md)",
            path.display()
        );
    }
    let fragment_type = parts[1];
    let Some(entry) = FRAGMENT_TYPES.iter().find(|t| t.name == fragment_type) else {
        bail!(
            "Changelog fragment {} has unrecognized type '{}' (valid types: {})",
            path.display(),
            fragment_type,
            FRAGMENT_TYPES
                .iter()
                .map(|t| t.name)
                .collect::<Vec<_>>()
                .join("|")
        );
    };
    let breaking = entry.breaking;

View on GitHub (pinned to 0d4ab78a4f)