Skip to content

Frequent apply_patch failures after 0.117.0 appear to come from the execution/runtime path, not from patch grammar parsing #16102

@jasontan656

Description

@jasontan656

What version of Codex CLI is running?

117

What subscription do you have?

200usd

Which model were you using?

gpt 5.4

What platform is your computer?

No response

What terminal emulator and version are you using (if applicable)?

No response

What issue are you seeing?

Title
Frequent apply_patch failures after 0.117.0 appear to come from the execution/runtime
path, not from patch grammar parsing

Session Reference
Codex session id: "019d310c-4996-7d52-b3e6-67a59ad0d0ad"

Summary
After upgrading to codex-cli 0.117.0, I started seeing apply_patch fail much more
frequently than before.

After reviewing the target session log and the current open-source Codex code, my
conclusion is:

  • This does not look like a primary apply_patch parser/grammar regression.
  • It looks much more like an execution-path regression around the runtime/delegation layer
    that actually runs the verified patch.
  • The timing strongly overlaps with 0.117.0 changes that made the app-server TUI default
    and refactored execution/environment handling through exec-server abstractions.

Why I do not think this is mainly a patch grammar problem
In the referenced session, the failures are not all the same kind.

I found at least three distinct failure classes:

  1. Invalid patch target type
    The session attempted to patch a compiled .pyc file under pycache, which failed
    with:
    stream did not contain valid UTF-8

That is not a parser regression. That is a bad patch target.

  1. Invalid patch body
    The session also produced:
    apply_patch verification failed: invalid hunk at line 4, Update hunk does not contain
    any lines

This matches current open-source parser behavior exactly. The parser still explicitly
rejects empty update hunks.

  1. Execution-layer ENOENT
    The most interesting failures were repeated:
    execution error: Io(Os { code: 2, kind: NotFound, message: "No such file or
    directory" })

These happened after the patch had already been parsed and verified well enough to
construct a changes payload. That strongly suggests the failure happened after
verification, during actual patch execution.

This is the key reason I do not think the main issue is grammar parsing.

What looks more likely
Current open-source Codex still routes apply_patch through a verify-then-delegate model:

  • the patch is parsed and verified first
  • then the runtime delegates execution by re-invoking Codex itself using:
    codex --codex-run-as-apply-patch

Relevant source files:

  • codex-rs/core/src/tools/handlers/apply_patch.rs
  • codex-rs/core/src/tools/runtimes/apply_patch.rs
  • codex-rs/arg0/src/lib.rs
  • codex-rs/apply-patch/src/parser.rs
  • codex-rs/apply-patch/src/lib.rs

This means apply_patch is more sensitive than a normal file write to issues in:

  • executable path resolution
  • self-reexec program path
  • app-server / exec-server environment handoff
  • sandbox command construction
  • cwd/path canonicalization
  • wrapper / dispatch behavior

If any of those drift, apply_patch can still pass verification and then fail later with
ENOENT during execution.

Why 0.117.0 is suspicious
The timing lines up with two important upstream changes:

  1. App-server TUI enabled by default
    PR: Enable tui_app_server feature by default #15661 “Enable tui_app_server feature by default”
    Enable tui_app_server feature by default #15661
  2. Exec/environment refactors just before that
    PR: Move environment abstraction into exec server #15125 “Move environment abstraction into exec server”
    Move environment abstraction into exec server #15125

PR: #15232 “Refactor ExecServer filesystem split between local and remote”
#15232

PR: #15233 “Split exec process into local and remote implementations”
#15233

Those changes are much closer to the observed symptom than any parser-specific change.

What I did not find
I did not find evidence that 0.117.0 introduced a major parser tightening for apply_patch.

In fact, the parser still appears lenient:

  • PARSE_IN_STRICT_MODE = false
  • earlier upstream changes even relaxed patch marker handling rather than tightening it

I also checked a recent apply_patch-related PR in the 0.117 window:

That change affects result surfacing/output behavior, not parser semantics or patch file
application logic.

Important session-specific observation
In the target session, some failing patch attempts were followed by shell checks showing
that the target file still existed and was visible from the expected path.

That makes the repeated ENOENT even more suspicious as an execution-path problem rather
than a missing target file problem.

There was also visible runtime surface drift in the same session:

  • old Python-oriented skill entry surfaces were still being read
  • new TypeScript-oriented runtime files were being generated

I do not think the TypeScript migration itself is the root cause, but it may have
increased the chance of exposing an execution-path bug.

Likely root-cause direction
My current best hypothesis is:

apply_patch became more failure-prone in 0.117.0 because the runtime path that delegates
verified patches into actual execution changed, likely due to app-server / exec-server
default-path changes, and not because patch syntax validation became stricter.

  • whether sandbox/path canonicalization causes the delegated executable or working
    directory to become unresolved

Short conclusion
This looks like an apply_patch execution/runtime regression, not primarily a parser
regression.

The strongest signal is that the session contains repeated post-verification ENOENT
failures, while current open-source parser behavior remains broadly lenient and unchanged
in the ways that would explain this pattern.

What steps can reproduce the bug?

Uploaded thread: 019d33a5-9976-73f3-b05f-6fb0802c5c13
Codex issue session id: "019d310c-4996-7d52-b3e6-67a59ad0d0ad"

What is the expected behavior?

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtool-callsIssues related to tool calling

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions