{"record":{"id":"467d77a1bcde4772","repo":"cross-rs/cross","slug":"changelog-entry-line-without-header","errorCode":null,"errorMessage":"changelog entry \"{line}\" without header","messagePattern":"changelog entry \"(.+?)\" without header","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xtask/src/changelog.rs","lineNumber":419,"sourceCode":"        .ok_or(eyre::eyre!(\"could not find the next release section\"))?;\n    let (section, footer) = rest.split_at(last_index);\n\n    // the unreleased should have the format:\n    //  ## [Unreleased] - ReleaseDate\n    //\n    //  ### Added\n    //\n    //  - #905 - ...\n    let mut kind = None;\n    let mut changes = Changes::default();\n    for line in section {\n        let line = line.trim();\n        if let Some(header) = line.strip_prefix(\"### \") {\n            kind = Some(ChangelogType::from_header(header)?);\n        } else if let Some(entry) = line.strip_prefix(\"- \") {\n            match kind {\n                Some(kind) => changes.push(ChangelogEntry::parse(entry, kind)?),\n                None => eyre::bail!(\"changelog entry \\\"{line}\\\" without header\"),\n            }\n        } else if !(line.is_empty() || line == \"## [Unreleased] - ReleaseDate\") {\n            eyre::bail!(\"invalid changelog entry, got \\\"{line}\\\"\");\n        }\n    }\n\n    Ok((header.join(\"\\n\"), changes, footer.join(\"\\n\")))\n}\n\nfn delete_changes(root: &Path) -> cross::Result<()> {\n    // move all files to the denoted version release\n    for entry in fs::read_dir(root.join(\".changes\"))? {\n        let entry = entry?;\n        let file_type = entry.file_type()?;\n        let srcpath = entry.path();\n        let ext = srcpath.extension();\n        if file_type.is_file() && ext.is_some_and(|v| v == \"json\") {\n            fs::remove_file(srcpath)?;","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/cross-rs/cross/blob/8c1a8aa4b661711f4b7b6ac07c2e8929ce2f7d27/xtask/src/changelog.rs#L401-L437","documentation":"read_changelog parses the changelog line by line. A '- ' entry line is only accepted after a '### <section>' header has established the current ChangelogType; if an entry appears before any header (or after the parser lost track), it bails with this error. It enforces that every entry belongs to a declared section.","triggerScenarios":"CHANGELOG.md has '- some entry' lines at the top of the file or directly after '## [Unreleased]' without a preceding '### Section' header; or an earlier invalid header line aborted kind assignment (note from_header's ? already propagates that).","commonSituations":"Hand-edited changelog where a contributor appends bullet points above the section headers, merges conflict resolution dropped a '### Fixed' line, or a template copied without its headers.","solutions":["Move the '- ' entry lines under the appropriate '### Added'/'### Fixed'/etc. header","Re-add the missing '### <section>' header above the orphaned entries","Regenerate the changelog with the xtask tooling instead of hand-editing"],"exampleFix":"// before\n## [Unreleased] - ReleaseDate\n- my change\n// after\n## [Unreleased] - ReleaseDate\n### Added\n- my change","handlingStrategy":"validation","validationCode":"let mut saw_header = false;\nfor line in text.lines() {\n    if line.starts_with(\"### \") { saw_header = true; }\n    if line.starts_with(\"- \") && !saw_header {\n        panic!(\"entry before any section header: {line}\");\n    }\n}","typeGuard":null,"tryCatchPattern":"match read_changelog(dir) {\n    Ok(changes) => changes,\n    Err(e) => { eprintln!(\"changelog format error, fix headers before entries: {e}\"); std::process::exit(1); }\n}","preventionTips":["Always place '### <section>' headers immediately after '## [Unreleased]' before adding bullets","Run the changelog validation (validate_changelog) in CI on docs changes","Avoid manual merge-conflict edits that drop header lines"],"tags":["changelog","parse","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"8c1a8aa4b661711f4b7b6ac07c2e8929ce2f7d27","analyzedAt":"2026-09-13T15:10:43.988Z","contentChangedAt":"2026-09-13T15:10:43.988Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}