Windows apply_patch invalid-base64 failures and silent large-file truncation
Environment
- Codex desktop app:
OpenAI.Codex 26.715.8383.0 - Platform: Microsoft Windows NT
10.0.26200.0, x64 - PowerShell:
7.6.3 - Surface: Codex desktop local workspace
- Date reproduced: 2026-07-22
Summary
On Windows, apply_patch corrupts some large text-file edits in two ways. It
either fails before hunk matching because the filesystem bridge returns
undecodable dataBase64, or reports success after silently truncating the
target file. One-line edits to generated ASCII-only files reproduce both modes
without any repository source, secrets, logs, or user data.
Sanitized reproduction
- Run
generate_repro.ps1. It createssynthetic_10000000_crlf.txt, exactly
10,000,000 bytes of deterministic ASCII filler. Its SHA-256 is
6BF7239738A80E81DBBFD4EEF1812F1752C7CFFFE22A662E013EF99FD3875017.
```powershell
param(
[long]$TargetSize = 10000000,
[string]$OutputPath = ""
)
if (-not $OutputPath) {
$OutputPath = Join-Path $PSScriptRoot (
"synthetic_{0}_crlf.txt" -f $TargetSize
)
}
$header = "PATCH_PROBE_ANCHOR = 0rn"
$bodyLine = (
"SAFE_SYNTHETIC_ASCII_CONTENT_0123456789" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz = fillerrn"
)
$encoding = [Text.Encoding]::ASCII
$remaining = $TargetSize - $encoding.GetByteCount($header)
$repeat = [Math]::Ceiling(
$remaining / $encoding.GetByteCount($bodyLine)
)
$bytes = $encoding.GetBytes($header + ($bodyLine * $repeat))
[Array]::Resize([ref]$bytes, $TargetSize)
[IO.File]::WriteAllBytes($OutputPath, $bytes)
Get-Item -LiteralPath $OutputPath | Select-Object FullName, Length
Get-FileHash -Algorithm SHA256 -LiteralPath $OutputPath
```
- Confirm that the first line is:
``text``
PATCH_PROBE_ANCHOR = 0
- Use Codex
apply_patchto replace only that line with:
``text``
PATCH_PROBE_ANCHOR = 1
- To probe the intermittent silent-truncation range, regenerate with, for
example, ./generate_repro.ps1 -TargetSize 5991281. Record the byte length,
apply the same one-line patch, and record the byte length again even when the
tool reports success.
Actual result
The patch failed before applying the hunk in three consecutive attempts:
Failed to read file to update ...\synthetic_repro.txt:
fs/readFile returned invalid base64 dataBase64:
Invalid symbol 61, offset 8467288
Invalid symbol 61, offset 8459096
Invalid symbol 61, offset 8459095
Another sanitized boundary probe returned:
Invalid input length: 6004737
The explicit failed reads did not mutate their sanitized targets in the latest
probe. However, multiple calls that returned success changed the requested
first line and silently removed data from later in the file:
| Expected bytes | Actual bytes | Bytes lost | Tool result |
|---:|---:|---:|---|
| 4,194,304 | 4,194,304 | 0 | success |
| 4,456,448 | 4,087,808 | 368,640 | success |
| 4,503,552 | 4,405,248 | 98,304 | success |
| 4,600,000 | 4,415,680 | 184,320 | success |
| 4,650,000 | 4,244,495 | 405,505 | success |
| 4,716,000 | 4,445,664 | 270,336 | success |
| 5,991,281 | 4,989,809 | 1,001,472 | success |
The first line in every successful case changed from 0 to 1, proving the
patch ran. The unexpected byte loss occurred elsewhere in the target.
The sanitized successful-call truncations are sufficient to show that a
reported success can be destructive.
Expected result
The one-line edit should apply without changing unrelated bytes. A successful
result must never truncate the target. If the file is unsupported,apply_patch should reject it before any mutation with a stable, explicit
size/capability error, and multi-file application should be atomic or clearly
transactional per target.
Investigation results
- Reproduces using deterministic generated ASCII; proprietary source is not
involved.
- Explicit failures occur before hunk matching, in the
fs/readFile/
dataBase64 path.
- Small files patch normally.
- A 10,000,000-byte sanitized fixture failed in three consecutive attempts.
Around 5-6 MB, results were intermittent and changed with file/content/path
layout. CRLF and a literal equals sign are not independently required.
- Nine nominally successful one-line probes silently truncated their targets;
losses ranged from 36,864 to 1,001,472 bytes.
- The same edit mechanism can be avoided with a reviewed unified patch using
separate git apply --check and git apply operations.
- Searching
openai/codexissues for the exact error returned no duplicate on
2026-07-22. Existing Windows apply_patch issues concern sandbox latency,
split writable roots, or large patch payloads rather than large target-file
base64 decoding.
Root-cause assessment
Confirmed proximate cause: the patch engine's large-file read/write transaction
does not reliably preserve the complete target bytes. Some filesystem-bridge
payloads are rejected as invalid base64; other incomplete payloads are accepted,
patched, and written back as shorter files.
Inference requiring maintainer confirmation: the size/layout sensitivity,
varying offsets for identical bytes, and interior padding error are consistent
with independently encoded, truncated, or nondeterministically segmented chunks
being combined without preserving a valid single base64 stream. The client-side
evidence cannot identify the exact encoder, chunk boundary, scheduling condition,
or transport cap.
Suggested fix
- Return raw bytes through a binary-safe transport or decode each independently
encoded chunk before concatenation.
- If one base64 value is required, encode the complete byte sequence once and
validate its length before returning it.
- Add regression tests around 4-7 MB text files with LF, CRLF, varied line
lengths, and file paths containing spaces.
- Validate the complete pre-edit byte length/hash and the calculated post-edit
byte length before replacing the target. Write to a sibling temporary file,
validate it, then atomically replace the original.
- Make multi-file patch failure atomic, or do not mutate any target until every
target has been read and all hunks have been validated.
- Return an explicit
target file exceeds supported patch-read sizeerror if a
hard limit is intentional.
Current safe workaround
For affected large files, create one bounded unified patch, rungit apply --check, then run git apply separately. Immediately verify file
existence, hash/diff scope, and syntax. Do not include an affected large file in
a multi-file apply_patch call.
Privacy
This report and generator contain no project source, repository names, secrets,
account identifiers, session transcript, or original logs.