fix(codex): BSD-safe temp-file creation on macOS (mktemp suffix + trailing-slash TMP_ROOT)#2103
Open
ShuratCode wants to merge 1 commit into
Open
fix(codex): BSD-safe temp-file creation on macOS (mktemp suffix + trailing-slash TMP_ROOT)#2103ShuratCode wants to merge 1 commit into
ShuratCode wants to merge 1 commit into
Conversation
…iling-slash TMP_ROOT) On macOS, /codex (all three modes) failed before Codex ever ran: the mktemp calls that create the stderr/prompt/response temp files errored out, the bash block exited 1, and the user got no review. Two compounding, independent bugs. 1. Suffix after the placeholder. The codex skill used templates like `mktemp "$TMP_ROOT/codex-err-XXXXXX.txt"` (also codex-prompt / codex-resp). GNU mktemp tolerates a suffix after the X run, but BSD mktemp (macOS) does not substitute the X's at all when the placeholder isn't at the end — so call garrytan#1 creates a LITERAL `codex-err-XXXXXX.txt` (exit 0) and a later call (a second /codex run, a stale leftover, or a concurrent worktree) fails with `mkstemp failed: File exists` and aborts. The failure is state-dependent, which is why some macOS users saw /codex "work." Fix: move the placeholder to the end of every codex mktemp template (drop the `.txt` suffix) in codex/SKILL.md.tmpl, regenerate codex/SKILL.md. 2. Trailing slash in TMP_ROOT. bin/gstack-paths emitted TMP_ROOT straight from $TMPDIR, which on macOS ends in `/` (e.g. /var/folders/.../T/), so "$TMP_ROOT/codex-err-..." expanded with a double slash. Fix: strip the trailing slash at the source so every consumer benefits, not just /codex (a bare "/" is preserved, not collapsed to empty). Both fixes are needed; the suffix bug is independent of the slash bug. Adds test/regression-issue2091-codex-bsd-mktemp.test.ts: a static invariant that no codex mktemp template carries a suffix after XXXXXX (asserted across both the .tmpl and the generated SKILL.md so regen drift can't reopen it), plus runtime checks that gstack-paths normalizes the trailing slash. Reported-by: Scott Hardin (@scotthardin) Refs garrytan#2091 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2091.
On macOS,
/codex(all three modes) fails before Codex ever runs: themktempcalls that create the stderr/prompt/response temp files error out, the bash block
exits 1, and the user gets no review. Two compounding but independent bugs,
both in gstack. Diagnosis credit to Scott Hardin (@scotthardin) in #2091 —
this PR implements his suggested fix.
Root causes
1. Suffix after the
mktempplaceholder (BSD vs GNU).The codex skill used templates like
mktemp "$TMP_ROOT/codex-err-XXXXXX.txt"(also
codex-prompt-XXXXXX.txt,codex-resp-XXXXXX.txt). GNUmktemptoleratesa suffix after the
XXXXXXrun; BSDmktemp(macOS) requires the placeholderat the end of the template and does not substitute the X's at all when a suffix
follows. So call #1 creates a literal fixed-name file
codex-err-XXXXXX.txtand exits 0, and a later call — a second
/codexrun, a stale leftover, or aconcurrent worktree — fails with
mkstemp failed: File exists, exits 1, and theempty
TMPERR/_PROMPT_FILEvars cascade into "No such file or directory". Thisis why the failure is state-dependent, and why some macOS users think
/codex"works."2. Trailing slash in
TMP_ROOT.bin/gstack-pathsemittedTMP_ROOTstraight from$TMPDIR, which on macOS endsin
/(e.g./var/folders/.../T/), so"$TMP_ROOT/codex-err-…"expands to adouble-slash path (
…/T//codex-err-…), compounding the failure.The fix
bin/gstack-paths: strip the trailing slash fromTMP_ROOTat the source(
_tmp_root="${_tmp_root%/}"), so every consumer benefits, not just/codex. A bare/is preserved (not collapsed to empty).codex/SKILL.md.tmpl(+ regeneratedcodex/SKILL.md): move the placeholderto the end of every codex
mktemptemplate (drop the.txtsuffix), at allfive sites (
codex-err×3,codex-prompt×1,codex-resp×1).Both changes are needed — the suffix bug is independent of the slash bug.
Verified repro (macOS 26.x, Apple Silicon, gstack 1.58.4.0,
/usr/bin/mktemp= BSD,$TMPDIRends in/)Before (old template, BSD mktemp):
After (new template + slash-normalized root):
Tests
test/regression-issue2091-codex-bsd-mktemp.test.tspins both bugs:mktemptemplate carries a non-Xsuffix after
XXXXXX, asserted across bothcodex/SKILL.md.tmpland thegenerated
codex/SKILL.mdso regen drift (or editing one but not the other)can't reopen it.
gstack-pathsstrips a trailing slash fromTMPDIR/TMP,leaves a clean path unchanged, and never collapses
/to empty.codex/SKILL.mdwas regenerated viabun run gen:skill-docs --host all, so theskill-docsdry-run CI check stays green.Same-class occurrences found — left out of scope (follow-ups)
Grepping
mktemp .*XXXXXX\.(txt|json|md)repo-wide surfaced the samesuffix-after-placeholder antipattern elsewhere. These are not on the
/codexpath (#2091) and use hardcoded
/tmprather than$TMP_ROOT, so I kept this PRfocused and reviewable rather than silently expanding it:
claude/SKILL.md.tmpl:98-99—mktemp /tmp/gstack-claude-response-XXXXXX.jsonand
mktemp /tmp/gstack-claude-error-XXXXXX.txt.scripts/resolvers/review.ts:354—mktemp /tmp/gstack-codex-oh-XXXXXXXX.txt(this is the source that generates
office-hours/SKILL.md:1303).Happy to fold these into this PR or send a follow-up — your call.