Skip to content

fix(mktemp): X's must be trailing — breaks on macOS (2nd run) and Alpine (1st run) (#2370) - #2372

Open
noron12234 wants to merge 1 commit into
garrytan:mainfrom
noron12234:fix/2370-mktemp-suffix
Open

fix(mktemp): X's must be trailing — breaks on macOS (2nd run) and Alpine (1st run) (#2370)#2372
noron12234 wants to merge 1 commit into
garrytan:mainfrom
noron12234:fix/2370-mktemp-suffix

Conversation

@noron12234

Copy link
Copy Markdown

Fixes #2370.

Scope

The issue reports the five mktemp templates in codex/SKILL.md.tmpl. The same
mistake exists in three more places it doesn't mention, so this PR fixes all of them:

file sites template
codex/SKILL.md.tmpl 5 codex-{err,prompt,resp}-XXXXXX.txt#2370
claude/SKILL.md.tmpl 3 …-response-XXXXXX.json, …-error-XXXXXX.txt, …-diff-XXXXXX.patch
scripts/resolvers/review.ts 1 gstack-codex-oh-XXXXXXXX.txtoffice-hours/SKILL.md
bin/gstack-developer-profile 2 developer-profile.json.XXXXXX.tmp

claude/SKILL.md.tmpl is the clearest tell — line 97 is already correct and the two
lines directly under it are not:

PROMPT_FILE=$(mktemp /tmp/gstack-claude-prompt-XXXXXX)        # correct
RESP_FILE=$(mktemp /tmp/gstack-claude-response-XXXXXX.json)   # broken
ERR_FILE=$(mktemp /tmp/gstack-claude-error-XXXXXX.txt)        # broken

Measured behaviour

Three platforms, same two templates:

codex-err-XXXXXX.txt (old) codex-err-XXXXXX (new)
macOS (BSD mktemp) run 1 creates a file named literally codex-err-XXXXXX.txt; run 2+ → mkstemp failed … File exists fresh name every run
Alpine (busybox mktemp) mktemp: : Invalid argument on every run, including the first fresh name every run
Debian (GNU coreutils 9.7) works — substitutes and keeps the suffix works
# macOS
run 1: /var/…/codex-err-XXXXXX.txt
run 2: mktemp: mkstemp failed on /var/…/codex-err-XXXXXX.txt: File exists
run 3: mktemp: mkstemp failed on /var/…/codex-err-XXXXXX.txt: File exists

# Alpine
run 1: mktemp: : Invalid argument
run 2: mktemp: : Invalid argument

Only GNU tolerates a suffix, which is why this survived — Linux CI is green while
macOS and Alpine users hit it. Note Alpine fails on the first run, so it's not even
the delayed failure mode the issue describes.

bin/gstack-developer-profile fails differently: its trap 'rm -f "$TMPOUT"' EXIT
usually cleans the literal file up, so single runs look fine. But the name is constant,
so two concurrent invocations collide on the same path and one process's trap deletes
the other's temp file — exactly the guarantee mktemp exists to provide:

old: A → /…/developer-profile.json.XXXXXX.tmp
     B → mktemp: mkstemp failed … File exists
new: A → developer-profile.json.tmp.hpkoP3
     B → developer-profile.json.tmp.JHnL0U

Fix

Move the X's to the end. The suffixes aren't load-bearing — nothing globs on them and
every cleanup is rm -f "$VAR" — so they're dropped. developer-profile keeps its
.tmp marker, moved ahead of the X's.

Verification

  • Generated docs rebuilt with bun run gen:skill-docs; the tracked diff is exactly
    6 files / 17 lines and every changed line is a mktemp line (git diff -U0
    filtered on non-mktemp content comes back empty).
  • bun test test/gen-skill-docs.test.ts test/gen-skill-docs-idempotency.test.ts test/gen-skill-docs-out-dir.test.ts test/codex-hardening.test.ts436 pass, 0 fail.

Not included

The issue also notes the temp files are never cleaned up (rm -f "$TMPERR" missing on
some paths) and that stale codex-err-review-XXXXXX.txt artifacts from older revisions
linger. That's a separate change to the skill's control flow — happy to follow up if
you want it in the same pass.

BSD mktemp (macOS) only substitutes X's when they are the trailing
characters of the template. With a suffix it creates a file whose name
contains six literal X's, then every later run fails with
"mkstemp failed: File exists" until TMPDIR is cleared. busybox mktemp
(Alpine) is worse -- it rejects the template outright on the first run.

Fixes the five sites in codex/SKILL.md.tmpl reported in garrytan#2370, plus the
same bug in three places the issue didn't cover:

  claude/SKILL.md.tmpl          RESP_FILE/.json, ERR_FILE/.txt, DIFF_FILE/.patch
                                (PROMPT_FILE one line above was already correct)
  scripts/resolvers/review.ts   CODEX_PROMPT_FILE/.txt -> office-hours/SKILL.md
  bin/gstack-developer-profile  developer-profile.json.XXXXXX.tmp, x2

The suffixes carry no meaning -- nothing globs on them, cleanup is by
variable -- so they are dropped. developer-profile keeps its .tmp marker,
moved ahead of the X's.

Generated SKILL.md files regenerated with bun run gen:skill-docs.
@trunk-io

trunk-io Bot commented Jul 28, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/codex: mktemp templates put X's before a .txt suffix — breaks on macOS after the first run, and the failure looks like a model stall

1 participant