Skip to content

Background tasks have no turn-timeout — a stalled first model request hangs the turn forever at task_started #489

Description

@Markiss-88

Summary

A --background Codex task can hang indefinitely when the turn's first model request stalls (e.g. a transient token-refresh / network stall in the detached, headless context). There is no turn-timeout or stall-heartbeat, so the turn stays parked at task_started forever, then the detached process eventually dies silently — producing no output and no error to the caller.

What we observed

A background delegation stalled and never recovered. The evidence:

  • Job log stops at the turn boundary and never advances:

    Starting Codex Task.
    Queued for background execution.
    Starting Codex task thread.
    Thread ready (<thread-id>).
    Turn started (<turn-id>).
    

    …and nothing after that.

  • Rollout JSONL for the thread contains only the opening events and then stops:

    session_meta
    event_msg: thread_settings_applied  (model set, provider openai)
    event_msg: task_started
    

    No model response, no tool calls, no completion, no error event — the file simply stops growing.

  • The detached process is gone; the caller gets no result and no failure signal (it just waits).

It is not the model / auth / prompt

The same model + same prompt via foreground codex exec completes normally in ~40s. So the model, the ChatGPT-plan auth (token refreshes fine on-demand), and the prompt are all fine. The failure is specific to the background path lacking a timeout/recovery around the first model request.

Impact

Anyone delegating real work via --background can silently lose an entire task to a single transient stall, with no error to react to. A caller that just polls for completion waits forever.

Suggested fix

Add a turn-timeout or stall-heartbeat on background turns: if the rollout hasn't advanced past task_started (no new events) within N seconds, abort the turn with a visible error the caller can catch and retry — fail loudly and recoverably instead of hanging forever. A configurable timeout (e.g. background_turn_timeout_sec) would let callers tune it.

As a stopgap on the caller side, a stall can be detected externally by watching the rollout JSONL for growth: if the last event is still task_started / thread_settings_applied and the file hasn't grown for a few minutes, treat the task as dead and retry foreground. But a built-in timeout would be the right fix.

Environment

  • codex-cli 0.144.1
  • Claude Code Codex plugin, background (detached) task mode
  • macOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions