Skip to content

v1.12: Linux run never returns after the turn completes; job dies on timeout with the output file already written #150

Description

@wjarka

Summary

Since v1.12, a sufficiently heavy Run Codex review step never completes on Linux. (See the control run in the comments: light runs on v1.12 finish fine, and v1.11 handles the same heavy workload cleanly.) Codex finishes the turn, writes its output file, prints its final message and token count — and then the step sits idle until the job's timeout-minutes kills it. The run is billed and discarded even though the result was already on disk.

The same workflow on v1.11 (52fe01ec70a42f454c9d2ebd47598f9fd6893d56) completes cleanly in ~87s.

Timeline from one affected run

ubuntu-latest, GitHub-hosted, runner 2.336.0, openai/codex-action@v1 resolving to 86365089eb2b84e0a8fb0717b304f8bdcb13b20e (v1.12):

Time (UTC) Event
06:40:48 job starts
06:40:56 Run Codex review starts
06:47:45 last exec completes
06:47:51 final assistant message, then tokens used / 270,199
06:47:51 → 06:55:48 nothing at all
06:55:48 job timeout-minutes: 15 deadline
07:00:49 force-killed, job cancelled

The step produced its full result in 6m55s, then idled for 7m57s.

The tell is the missing end marker. On v1.11 the log reads:

<token count>
##[end-action id=__openai_codex-action.run_codex;outcome=success;conclusion=success;duration_ms=86604]

On v1.12 the token count is the last line the step ever emits. No end-action, no outcome.

Configuration

      - uses: openai/codex-action@v1
        with:
          openai-api-key: ${{ secrets.OPENAI_API_KEY }}
          prompt-file: <path>
          output-file: <path>
          working-directory: <path>
          model: gpt-5.6-luna
          effort: xhigh
          sandbox: read-only
          output-schema-file: <path>

Raising timeout-minutes does not help — the step idles longer. Lowering effort does not help either; the turn was never the slow part.

Why this loses completed work

With an explicit output-file, runCodexExec passes --output-last-message <file> straight to codex exec, so the CLI writes the result itself as soon as the turn ends. In the run above the file existed at 06:47:51.

But because the step never returns, every later step in the job is skipped — including the artifact upload that hands the result to the next job. A finished, valid, schema-conforming result is thrown away. Consumers that treat step success as "a result exists" will silently produce nothing.

Suspected area

v1.12 is the first release to route Codex through the rewritten privilege-isolation path (src/dropSudo.ts +419/-20, src/runCodexExec.ts +285/-6, new src/linuxCredentials.ts), launching via:

/usr/bin/setpriv --reuid="$uid" --regid="$nobody_gid" --clear-groups \
  --no-new-privs --bounding-set=-all --inh-caps=-all --ambient-caps=-all \
  -- /usr/bin/env ... "$@"
exec "$@"

A plausible mechanism is a descendant process surviving the turn and holding the inherited stdio pipe open, so the wrapper never observes stream close. Supporting detail: even on a clean v1.11 run, the runner's own cleanup reports leftovers —

Cleaning up orphan processes
Terminate orphan process: pid (2460) (bash)
Terminate orphan process: pid (2462) (MainThread)

That run was 87s and spawned few children, so it exited regardless. The affected run executed many subprocesses during the turn.

A second symptom from the same run may share a cause: subprocesses failing to create a temporary directory. Retracted — a v1.11 control run produces the same errors and finishes normally, so that is ordinary sandbox: read-only behaviour and unrelated to this issue. See the comment below.

Possibly related open issues: #103 (output-schema with runAsUser fails to create temporary file), #137 (failed runs leave temporary output directories behind), #108 (proxy hangs).

Two things that would help regardless of the root cause

  1. Bound the wait. If the wrapper waited on process exit with a timeout rather than on stdio close, a lingering descendant would cost seconds, not the whole job budget.
  2. Don't hide a written result. The output file is complete before the hang. Failing the step with a message naming the written file — instead of never returning — would let callers publish the result they already paid for.

Workaround

Pin to v1.11:

uses: openai/codex-action@52fe01ec70a42f454c9d2ebd47598f9fd6893d56  # v1.11

Note that v1 currently points at v1.12, so anyone on the floating tag picked this up automatically.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions