Hmbown/CodeWhale · error
patch missing *** Begin Patch header
Error message
patch missing *** Begin Patch header
What it means
`apply_patch` implements a strict single-file patch format. The very first line must equal `*** Begin Patch` exactly (eval.rs:682-686); anything else — including an empty first line caused by a leading newline — aborts before any file is read or written.
Source
Thrown at crates/tui/src/eval.rs:682
Ok(SearchResult { matches })
}
fn append_workspace_file(path: &Path, line: &str) -> Result<()> {
let mut content = read_workspace_file(path)?;
if !content.ends_with('\n') {
content.push('\n');
}
content.push_str(line);
content.push('\n');
fs::write(path, content).with_context(|| format!("failed to write {}", path.display()))
}
fn apply_patch(root: &Path, patch: &str) -> Result<()> {
let mut lines = patch.lines();
let begin = lines.next().unwrap_or_default();
if begin != "*** Begin Patch" {
return Err(anyhow!("patch missing *** Begin Patch header"));
}
let header = lines.next().unwrap_or_default();
let file_rel = header
.strip_prefix("*** Update File: ")
.ok_or_else(|| anyhow!("only *** Update File patches are supported"))?;
if file_rel.contains("..") {
return Err(anyhow!("patch path must be workspace-relative"));
}
let file_path = root.join(file_rel);
let original = read_workspace_file(&file_path)?;
let had_trailing_newline = original.ends_with('\n');
let mut file_lines: Vec<String> = original.lines().map(|l| l.to_string()).collect();
let mut cursor = 0usize;
for raw_line in lines {
if raw_line == "*** End Patch" {View on GitHub (pinned to 8880682c63)
Solutions
- Trim leading whitespace/newlines and ensure line 1 is exactly `*** Begin Patch`
- Convert foreign formats (unified diff) before calling apply_patch
- Validate the header before applying
Example fix
// before
let patch = raw_model_output;
// after
let patch = raw_model_output.trim_start();
assert_eq!(patch.lines().next(), Some("*** Begin Patch")); Defensive patterns
Strategy: validation
Validate before calling
fn patch_has_begin_header(patch: &str) -> bool {
patch.trim_start().lines().next() == Some("*** Begin Patch")
}
anyhow::ensure!(
patch_has_begin_header(&patch),
"model output lacks the *** Begin Patch header"
); Type guard
fn patch_has_begin_header(patch: &str) -> bool {
patch.trim_start().lines().next() == Some("*** Begin Patch")
} Try / catch
match apply_patch(&root, &patch) {
Err(err) if err.to_string().contains("*** Begin Patch") => {
// re-prompt the model for the full patch with the exact header
}
other => other?,
} Prevention
- Validate patch shape before touching disk
- Trim model output before parsing
- Re-prompt with the exact format contract on failure instead of patching text ad hoc
When it happens
Trigger: Model output omits the header; the patch string starts with a newline or whitespace; a unified diff or markdown-fenced block is passed instead of the expected format.
Common situations: LLM emits a different diff dialect; a prompt template or transport mangles the first line; hand-written patches missing the sentinel.
Related errors
- only *** Update File patches are supported
- unexpected patch directive: {raw_line}
- unsupported patch line: {raw_line}
- patch context not found in {}: {}
- patch removal mismatch in {}: expected '{}'
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/5dbc5e1ff05c9df6.
Report an issue: GitHub.