openai/codex · error · ParseError
invalid patch: {0}
Error message
invalid patch: {0} What it means
Raised by the apply-patch parser when the patch text does not conform to the grammar at the whole-patch level (start: begin_patch hunk+ end_patch). The {0} string carries the specific reason - typically a missing '*** Begin Patch' header or '*** End Patch' trailer. The parser runs lenient by default (PARSE_IN_STRICT_MODE = false, kept lenient for gpt-4.1 quirks), so this fires only on fundamentally broken input, not minor whitespace deviations; hunk-level problems use InvalidHunkError instead.
Source
Thrown at codex-rs/apply-patch/src/parser.rs:57
pub(crate) const ADD_FILE_MARKER: &str = "*** Add File: ";
pub(crate) const DELETE_FILE_MARKER: &str = "*** Delete File: ";
pub(crate) const UPDATE_FILE_MARKER: &str = "*** Update File: ";
pub(crate) const MOVE_TO_MARKER: &str = "*** Move to: ";
pub(crate) const EOF_MARKER: &str = "*** End of File";
pub(crate) const CHANGE_CONTEXT_MARKER: &str = "@@ ";
pub(crate) const EMPTY_CHANGE_CONTEXT_MARKER: &str = "@@";
/// Currently, the only OpenAI model that knowingly requires lenient parsing is
/// gpt-4.1. While we could try to require everyone to pass in a strictness
/// param when invoking apply_patch, it is a pain to thread it through all of
/// the call sites, so we resign ourselves allowing lenient parsing for all
/// models. See [`ParseMode::Lenient`] for details on the exceptions we make for
/// gpt-4.1.
const PARSE_IN_STRICT_MODE: bool = false;
#[derive(Debug, PartialEq, Error, Clone)]
pub enum ParseError {
#[error("invalid patch: {0}")]
InvalidPatchError(String),
#[error("invalid hunk at line {line_number}, {message}")]
InvalidHunkError { message: String, line_number: usize },
}
use ParseError::*;
#[derive(Debug, PartialEq, Clone)]
#[allow(clippy::enum_variant_names)]
pub enum Hunk {
AddFile {
path: PathBuf,
contents: String,
},
DeleteFile {
path: PathBuf,
},
UpdateFile {
path: PathBuf,View on GitHub (pinned to 339751715c)
Solutions
- Ensure the patch starts with '*** Begin Patch' and ends with '*** End Patch' on their own lines
- Strip surrounding markdown fences and prose before handing model output to apply_patch
- Check for truncation and regenerate the full patch
- Read the {0} detail - it names the exact structural problem
Example fix
// before
let patch = raw_model_output; // wrapped in ``` fences -> InvalidPatchError
// after
let patch = raw_model_output.trim()
.trim_start_matches('`').trim_start_matches("diff").trim()
.trim_end_matches('`').trim();
debug_assert!(patch.starts_with("*** Begin Patch") && patch.ends_with("*** End Patch")); Defensive patterns
Strategy: validation
Validate before calling
fn looks_like_patch(s: &str) -> bool {
s.starts_with("*** Begin Patch") && s.trim_end().ends_with("*** End Patch")
}
if !looks_like_patch(&model_output) {
return Err("model did not emit a bare patch");
} Type guard
fn is_invalid_patch(e: &ParseError) -> bool {
matches!(e, ParseError::InvalidPatchError(_))
} Try / catch
match apply_patch(patch, ...).await {
Err(failure) => match failure.into_parts().0 {
ApplyPatchError::ParseError(ParseError::InvalidPatchError(msg)) => {
eprintln!("patch malformed: {msg}"); // log raw patch alongside
}
other => return Err(other.into()),
},
Ok(_) => {}
} Prevention
- Strip markdown fences and prose from model output before applying
- Assert both markers are present before calling apply_patch
- Detect truncation (missing end marker) and re-request the full patch instead of parsing the fragment
When it happens
Trigger: Passing text without the '*** Begin Patch'/'*** End Patch' markers to apply_patch; model output wrapped in markdown fences or prose; a response truncated before the end marker; hand-built patch strings missing the markers.
Common situations: LLM output that surrounds the patch with ``` fences or explanations; streaming responses cut mid-patch; encoding corruption of the first/last lines.
Related errors
- invalid hunk at line {line_number}, {message}
- failed to decrypt encrypted task id
- approval_policy = "untrusted" is no longer supported; remove
- {error}
- No files were modified.
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/cb04c16a90ed79ed.
Report an issue: GitHub.