[macOS] Workspace diff SIGKILL leaves temporary Git objects behind, causing repeated disk exhaustion
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the Codex App are you using (From “About Codex” dialog)?
ChatGPT.app 26.901.41600, build 7982, with bundled codex-cli 0.153.4 at /Applications/ChatGPT.app/Contents/Resources/codex.
What subscription do you have?
Not included in this diagnostic report.
What platform is your computer?
Darwin 27.0.0 arm64 arm — macOS on Apple Silicon.
What issue are you seeing?
The background workspace-diff collector repeatedly creates temporary Git object databases, hashes large untracked files into them, then is killed with SIGKILL before its shell EXIT trap can remove them. Repeated collection can exhaust the system disk. In this incident, 212 temporary directories occupied approximately 91.95 GiB. Removing 173 inactive directories reclaimed approximately 74.17 GiB, but the collector continued creating new directories.
This report concerns temporary directories under the macOS user temporary root ($TMPDIR/tmp.*), containing index, index.lock, and objects. It is distinct from growth in the repository's normal .git/objects/pack or Git LFS directory.
The observed process chain is:
ChatGPT.app
-> bundled codex app-server
-> bash -c <workspace-diff collector script>
-> git ... add --pathspec-from-file=... --pathspec-file-nul
The shell invocation's argument tail is:
codex-workspace-diff unstaged false false false 1500 9000
The collector begins with this identifying comment:
# This script must not mutate the repository while collecting a workspace diff.
The captured collector script sets a temporary GIT_INDEX_FILE and GIT_OBJECT_DIRECTORY, registers trap cleanup EXIT, obtains untracked paths, and calls git add --pathspec-from-file on the entire untracked set before applying the later diff output limits. The workspace had 4,108 untracked files totaling approximately 8.55 GiB, including more than 5 GiB of generated video artifacts in a root-level scratch directory that was not ignored by Git.
What steps can reproduce the bug?
The following conditions describe the real workspace where two consecutive background collections were directly observed. A separate synthetic fixture has not yet been tested.
- Open a Git workspace in the app with several thousand untracked files, including multiple GiB of large binary artifacts that are not ignored.
- Use the task normally so the app requests the unstaged workspace diff. No user-requested staging or commit is needed.
- Observe the bundled app-server launch the workspace-diff shell identified above.
- Monitor the shell's temporary Git directory and its process exit status.
- Repeat the refresh/normal use and observe that another temporary directory is allocated while the previous one remains.
Direct observations from two consecutive live runs:
| Run | Observed lifetime | Result | Temporary data remaining after shell exit |
|---|---|---|---|
| 1 | 19.64 seconds | Shell disappeared before cleanup | Approximately 624 MiB |
| 2 | 19.66 seconds | Shell disappeared before cleanup | Approximately 624 MiB |
For a directly monitored collector shell, macOS kqueue with NOTE_EXITSTATUS reported raw exit status 9, establishing termination by signal 9 (SIGKILL). The directory and objects remained after the shell exited. The observer did not kill the process.
What is the expected behavior?
Background workspace diff collection should have a bounded disk-write budget and should not leave large temporary object databases behind when it is canceled or killed.
Potential fixes:
- Apply file-size, file-count, and aggregate byte limits before hashing untracked contents, rather than only bounding the resulting diff.
- Have the parent own temporary-directory cleanup after it has reaped the collector and its children, including forced termination. A shell EXIT trap cannot handle SIGKILL.
- Use an identifiable application-owned temporary root and safely reclaim abandoned collector directories after interrupted sessions.
- Avoid repeatedly retrying the same oversized untracked set without backoff or a visible omitted-files result.
Additional information
Confirmed: the app-server launches this collector; its temporary Git database grows while hashing untracked content; signal 9 terminates a directly observed shell; its temporary directory survives; repeated collections create additional directories.
Not yet established: which component sends SIGKILL or why. The nearly identical ~20-second lifetimes suggest a deadline/cancellation path, but the timeout owner and exact trigger have not been traced. This report does not claim that timing alone proves an app timeout.
Verified local mitigation: added ignore rules only for generated media under the repository's root-level scratch directory (MOV, MP4, WebM, WAV, MP3, PNG, JPG/JPEG, and WebP, case-insensitive). Source files remain visible. This reduced the untracked set from 4,108 files / 8.55 GiB to 1,292 files / 68.04 MiB.
The exact captured collector script was then rerun with the same arguments in the same working directory. It completed in 0.77 seconds, exited 0, produced no stderr or commandFailed protocol result, and left no new temporary Git directories. This supports the large-untracked-content trigger and confirms that normal completion cleans up correctly. The ignore rules reduce exposure but do not repair the collector's cleanup and resource-budget defects.
Related reports were checked:
- #28750 and #41147 concern internal Git staging/snapshots exhausting the repository's object storage.
- #34953 concerns Git LFS temporary copies on Windows.
Those reports share the large-untracked-file trigger. This report adds the distinct macOS $TMPDIR/tmp.* workspace-diff path, captured SIGKILL exit status, and a cleanup trap that cannot run after that signal. No exact codex-workspace-diff report was found in the issue search.
All local usernames, private project paths, file names, and file contents have been omitted. No session transcript or credentials are attached.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the app-server entry point that launches the codex-workspace-diff shell collector and trace its temporary GIT_INDEX_FILE and GIT_OBJECT_DIRECTORY handling. Reproduce with the large untracked-file scenario, identify the SIGKILL or cancellation owner, and verify that interrupted collections stay within resource limits and reclaim temporary directories after the process is reaped.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, macos, rust, shell
- Domain
- desktop, devtools, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100