Codex bundled-marketplace refresh leaks staging directories and can consume tens of gigabytes #42049
neverdie88
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Codex Desktop repeatedly leaves abandoned bundled-marketplace staging directories under:
This caused severe disk exhaustion on macOS:
Root-cause evidence
The desktop updater:
Promise.alland macOSditto.openai-bundled.staging-*directories during startup.The abandoned directories were partially cleaned: manifests were missing, while different subsets of copied plugins remained. This is consistent with cleanup racing outstanding copy operations.
Each retained directory was approximately 100 MiB:
After the original cleanup, the problem reproduced live. Five new staging directories totaling approximately 503 MiB appeared within several minutes, despite approximately 33 GiB of available disk space. Therefore, low disk space increases the likelihood of failure but is not required to trigger the leak.
Additional contributing issues
Suggested fixes
dittoprocesses on failure.*.staging-*directories during startup.ENOSPC.Proposed implementation
Use a single interprocess lock for each managed marketplace and treat staging as a recoverable transaction:
Acquire an exclusive lock such as:
If another refresh owns the lock, reuse or wait for that refresh instead of creating another staging directory.
After acquiring the lock, remove abandoned
openai-bundled.staging-*directories older than a conservative threshold. Never remove the directory owned by the active refresh.Create one staging directory and record its ownership and start time. Check that available disk space is sufficient for the bundled marketplace plus a safety margin before copying.
Copy plugins with bounded concurrency. If any worker fails, cancel the remaining work and wait for every spawned
dittoprocess to exit before attempting cleanup.Promise.allSettledcan be used to ensure that all workers have finished; the first meaningful error should still be preserved for reporting.Validate the completed staging tree before promotion:
.codex-plugin/plugin.json.Promote without first destroying the working marketplace:
If the second rename fails, restore
openai-bundled.previous. Delete the previous version only after the new marketplace is validated and active.In
finally, wait for all child processes and remove staging with retry/backoff for transientEBUSY,ENOTEMPTY,EPERM,EMFILE, andENFILEfailures. Verify that the directory no longer exists before considering cleanup successful.Run the same stale-staging sweep during Codex startup so crashes, forced termination, and system restarts cannot leave permanent data behind.
Add a safety policy and telemetry:
The essential ordering is:
This removes the cleanup-versus-copy race, prevents concurrent refresh duplication, preserves the last working marketplace, and guarantees recovery after application termination.
Recovery performed
After confirming that the staging root contained only real directories matching the expected pattern and had no open handles, I removed only:
I recreated the empty parent directory. Sessions, state databases, memories, skills, plugins, configuration, credentials, and project data were preserved.
Environment
26.715.72359571826.6.1(25G76)The precise operation that first rejected could not be recovered because the relevant updater error was not retained locally. However, the staging lifecycle defects and live recurrence were directly verified.
All reactions