{"record":{"id":"9642da240604b967","repo":"vectordotdev/vector","slug":"invalid-fragment-contents-for-filename-last-line-must-be","errorCode":null,"errorMessage":"invalid fragment contents for '{filename}': last line must be 'authors: <name> [<name> ...]' (no trailing blank lines).","messagePattern":"invalid fragment contents for '(.+?)': last line must be 'authors: <name> \\[<name> \\.\\.\\.\\]' \\(no trailing blank lines\\)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vdev/src/commands/check/changelog_fragments.rs","lineNumber":201,"sourceCode":"    };\n    if parts[2] != \"md\" {\n        bail!(\"invalid fragment filename '{filename}': extension must be markdown (.md).\");\n    }\n    Ok(known)\n}\n\nfn validate_contents(\n    path: &std::path::Path,\n    filename: &str,\n    fragment_type: &FragmentType,\n) -> Result<()> {\n    let content = std::fs::read_to_string(path)?;\n    // Match generate_cue.rs, which reads `lines().last()` verbatim: the authors\n    // line must be the last line, no trailing blank lines allowed.\n    let last_line = content.lines().last().unwrap_or(\"\");\n\n    let Some(names) = last_line.strip_prefix(\"authors: \") else {\n        bail!(\n            \"invalid fragment contents for '{filename}': last line must be 'authors: <name> [<name> ...]' (no trailing blank lines).\"\n        );\n    };\n    let names = names.trim();\n    if names.is_empty() {\n        bail!(\"invalid fragment contents for '{filename}': authors line has no names.\");\n    }\n    if names.contains('@') {\n        bail!(\n            \"invalid fragment contents for '{filename}': author names should not be prefixed with '@'.\"\n        );\n    }\n    if names.contains(',') {\n        bail!(\n            \"invalid fragment contents for '{filename}': authors should be space delimited, not comma delimited.\"\n        );\n    }\n    if names.split_whitespace().any(|n| n == TODO_HANDLE) {","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/vdev/src/commands/check/changelog_fragments.rs#L183-L219","documentation":"The fragment's last line must be an `authors: <name> [<name> ...]` line, read verbatim via `lines().last()` to match generate_cue.rs. Trailing blank lines or a missing authors line break the release tooling's attribution parsing.","triggerScenarios":"Running `vdev check changelog-fragments` when the fragment body is the last line (no `authors:` line at all), the authors line is followed by blank lines, or `authors:` lacks the required `authors: ` prefix.","commonSituations":"Editor auto-trimming or adding a final newline plus blank line; hand-editing the scaffold and deleting the authors line; pasting content after the authors line.","solutions":["Ensure the very last line of the file is `authors: your_github_handle`.","Remove any blank lines after the authors line.","Re-run the scaffolder if the fragment structure is badly mangled."],"exampleFix":"// before\nSome change.\n\n// after\nSome change.\nauthors: jdoe","handlingStrategy":"validation","validationCode":"let content = std::fs::read_to_string(path)?;\nlet last = content.lines().last().unwrap_or(\"\");\nassert!(last.starts_with(\"authors: \") && !last.trim_end().is_empty(), \"last line must be 'authors: <names>'\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep `authors: handle` as the literal final line of every fragment.","Disable 'trim trailing newlines' editor settings that can mangle the ending, or verify the ending before committing.","Never append content below the authors line."],"tags":["rust","changelog","validation","ci"],"backgroundTag":"schema-validation-failed","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}