Windows apply_patch fails with STATUS_USER_MAPPED_FILE; desktop background Git mapping contention suspected
Summary
The built-in apply_patch intermittently reports only Failed to write file on Windows. An ETL captured the actual failure: opening the target succeeds, but truncation fails with NTSTATUS 0xC0000243 (STATUS_USER_MAPPED_FILE, Win32 error 1224).
A separate mapping-enabled trace proves that a desktop-app-launched Git diff maps the same target file for approximately 42.26 seconds. This is a concrete contention candidate, not proof that this particular process caused the earlier failure. Please investigate coordination between background Git reads and patch writes, and preserve the underlying OS error in tool output.
Environment
- Windows version reported by the local environment:
10.0.26200.0. - Desktop package observed:
OpenAI.Codex_26.911.7940.0_x64. - Bundled backend:
codex-cli 0.155.0-alpha.2.6. - Desktop process image name:
ChatGPT.exe; backend process:codex.exe. - Local Windows Git repository, existing uncommitted work preserved.
- Affected file:
tests/test_development_focus.py(repository root omitted here). - Timestamps below are UTC; captures occurred on 2026-09-17.
Expected and actual behavior
Expected: a valid patch either completes safely or reports a precise, actionable OS-level failure. Background repository inspection should not cause unexplained editing failures.
Actual: the tool reports a generic Failed to write file. The captured failure occurs after successful open and before replacement content is written. Retrying at a different time can succeed. No file-content corruption was observed in these probes; this is not a claim that all failure paths are corruption-safe.
Evidence A: original failed write
Trace: codex-patch-20260917-102113.etl.
Summary: 8,976,213 events, 93 seconds, zero reported lost events.
| UTC time | Operation | Result |
|---|---|---|
| 14:20:50.327428 | Target Create/open by codex.exe PID 11332 | Completes successfully at .327463 |
| 14:20:50.327485 | SetInfo, class 19, FileAllocationInformation, size 0 | 0xC0000243 at .327497 |
| 14:20:50.327505 | SetInfo, class 20, FileEndOfFileInformation, size 0 | 0xC0000243 at .327516 |
The failing request used file object 0xffffe3850b5ab150 and IRP 0xffffe38404ce6a88.
The file's SHA-256 was unchanged after diagnostic checks:
DB75230110A81C0A7CEEADB0DE179115A2F6616D86527EBB1B3E3D95CE5E03AF.
Evidence B: controlled mechanism reproduction
This reproduces mapped-section contention, not the full desktop Git race:
- Create a disposable text file containing
controlled diagnostic contentfollowed by a newline. - In a separate Python process, open it read-only, create a read-only
mmap, then close the ordinary file handle while keeping the mapping alive for 25 seconds. - During that interval, use the built-in patch tool to replace that line with itself.
- Observe
Failed to write file. - Release the mapping and retry the identical patch; it succeeds.
Use a disposable file only. Closing a normal file handle is not sufficient to prove that no mapping remains. The temporary file's content hash stayed unchanged through the test.
Evidence C: desktop Git mapping
Trace: codex-patch-mapping-20260917-1105.etl.
Summary: 1,226,183 events, 112 seconds, zero reported lost events.
This capture contains a successful patch, not another failed patch.
Process ancestry from ETL:
ChatGPT.exe (27152) -> git.exe (3316) -> git.exe (11392).
Observed Git command, with the baseline commit elided:
git.exe -c diff.mnemonicPrefix=false -c diff.noprefix=false
-c core.quotePath=false -c safe.bareRepository=explicit
-c core.hooksPath=NUL -c core.fsmonitor=
diff --no-ext-diff --no-textconv --color=never
--src-prefix=a/ --dst-prefix=b/ <baseline-commit>
--find-renames --raw --no-abbrev --numstat -z
The command above was observed in the trace, not issued as a diagnostic command by the agent.
- Target FileKey:
0xffffd108a8ebe180, correlated with the target's file operations. - PID 11392 mapped the target at
15:05:09.018836. - The same process unmapped the same view at
15:05:51.278718. - View base:
0x2d3fd070000; duration: 42.259882 seconds. - The patch's truncate completed successfully at
15:05:07.452225, before this mapping began.
In the original failed-write trace, another desktop-launched Git diff with the same arguments was already running: 27152 -> 23984 -> 896. Its process-end events occur at 14:20:52.268695 and 14:20:52.268738, after the write failure. Its creation predates the captured interval. The original trace lacks MapFile/UnmapFile events, so binding PID 896 to that original blocking mapping remains unproven.
Confidence and exclusions
- Confirmed: mapped-section conflict blocked the original truncate.
- Confirmed: the built-in tool collapses that failure into a generic message in the observed test.
- Confirmed: desktop background Git can keep this exact file mapped for tens of seconds.
- Strongly supported hypothesis: background Git mapping competes with patch truncation.
- Not confirmed: the exact original mapping owner, or a source-code-level defect in the desktop Git implementation.
- No evidence justifies blaming Defender, disabling protection, terminating arbitrary processes, or changing repository permissions.
- A delayed System close resolved to cache-manager teardown (
CcDeleteSharedCacheMap); this is not by itself proof of ownership of the blocking user mapping.
Requested engineering investigation and acceptance checks
These are proposed checks, not implemented fixes:
- Preserve NTSTATUS/Win32 error, operation and target context when patch writes fail.
- Inspect lifetime and coordination of desktop-owned Git mappings and foreground edits.
- Reproduce with a real background Git diff and a concurrent patch to the same disposable repository file; test both overlapping and non-overlapping lifetimes.
- Verify that failure leaves the original content intact, recovery does not overwrite intervening edits, and the tool never reports success without completing the write.
- Cover both desktop and standalone patch entrypoints. Do not treat disabling background Git or replacing files atomically as proven fixes without validating their semantics and safety.
The remaining historical attribution gap requires a failure and its mapping lifetime in the same capture. Further broad tracing is not currently proposed; capture that overlap on the next natural recurrence.
Attachments and privacy
Start with this report and the two small trace-summary text files. Full ETLs are retained locally for a secure follow-up request; do not upload them publicly by default. ETLs can contain unrelated process information, paths and command lines, and have not been comprehensively sanitized.
- Failed-write ETL: 1,971,322,880 bytes.
- Mapping-enabled ETL: 143,654,912 bytes.
- Optional reproduction configuration:
codex_patch_mapping.wprp. - Optional local analysis notes and parsers are available on request; none are attached here.
- Do not attach the entire repository, session history, or downloaded Microsoft PDB by default.
Reference definitions
- Microsoft NTSTATUS definitions:
STATUS_USER_MAPPED_FILE. - Microsoft PerfView kernel parser: FileIO MapFile/UnmapFile opcodes and MapFileTraceData layout used for decoding.
- Official troubleshooting and feedback guidance: review logs for sensitive information before sharing them.
Source: openai/codex