openai/codex · error · ParseError

invalid hunk at line {line_number}, {message}

Error message

invalid hunk at line {line_number}, {message}

What it means

Hunk-level syntax error: the patch as a whole parsed, but one hunk violates the grammar. Display embeds the 1-based line_number within the patch text and a message naming the violation - for example a change line missing its leading ' ', '+', or '-' prefix, an Update File hunk with no context/changes, a misplaced '*** End of File', or a malformed '*** Move to:'. Lenient mode tolerates gpt-4.1 quirks, so this variant indicates real structural damage inside a hunk.

Source

Thrown at codex-rs/apply-patch/src/parser.rs:59

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,
        move_path: Option<PathBuf>,

View on GitHub (pinned to 339751715c)

Solutions

  1. Go to the reported line_number in the patch text and fix the violation named in the message
  2. Verify every change line inside Update hunks starts with ' ', '+', or '-'
  3. Ensure the final line of the patch ends with a newline
  4. Regenerate the patch from the model or tool rather than hand-editing hunk syntax

Example fix

# before (line reported invalid: context line missing its leading space)
*** Update File: a.txt
@@ def main():
print("hi")

# after
*** Update File: a.txt
@@ def main():
 print("hi")
Defensive patterns

Strategy: try-catch

Type guard

fn is_invalid_hunk(e: &ParseError) -> bool {
    matches!(e, ParseError::InvalidHunkError { .. })
}

Try / catch

if let ApplyPatchError::ParseError(ParseError::InvalidHunkError { message, line_number }) = inner {
    // surface line_number to the user/model so the hunk can be self-corrected
    eprintln!("bad hunk at patch line {line_number}: {message}");
}

Prevention

When it happens

Trigger: A change line inside an Update hunk missing its context/add/remove prefix; an '*** Update File:' section with no @@ context or change lines; '*** End of File' used inside an Add hunk; the final patch line missing its trailing newline so the last hunk line is cut.

Common situations: A model emits hunk bodies with wrong prefixes; hand-edits damage a hunk; CRLF or whitespace mangling; copy-paste drops leading spaces on context lines.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/ddeece286c656942. Report an issue: GitHub.