Agent runs silently continue to the turn cap when Codex rejects every turn (codex/event/error only surfaced at debug) #92
derekrivers
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Summary
When the Codex model call is rejected on every turn — e.g. the configured model isn't available to the account or the installed CLI can't drive it — the app server emits a codex/event/error notification, but the run continues turn after turn until it reaches the turn cap, with no error surfaced above debug level. Each turn looks like a clean completion. The net effect is a run that silently consumes its entire turn budget, produces nothing, and gives operators no signal pointing at the real cause.
What happens
On each turn:
the app server receives codex/event/error, logged at debug only;
task_complete fires with last_agent_message: null;
the run loop records a normal completion ("Completed agent run … Continuing agent run … turn N/20") and re-dispatches.
Per-turn event sequence:
task_started → turn/started → item_started → item_completed → user_message →
codex/event/error → thread/status/changed → error → task_complete
(task_complete carries last_agent_message: null)
Because codex/event/error isn't surfaced above debug, and an empty turn is treated as a normal completion rather than a failure, nothing indicates that every turn is failing for the same reason.
Concrete case
A WORKFLOW.md pinned model="gpt-5.5" while the running Codex CLI (a snap build, 0.114.0) couldn't drive that model. Called directly, the real reason is obvious:
$ codex exec --config 'model="gpt-5.5"' "ping"
ERROR: {"detail":"The 'gpt-5.5' model requires a newer version of Codex…"}
Inside the agent loop, that same rejection appeared only as the debug-level codex/event/error, so the run produced ~20 empty turns and hit the cap. The trigger generalizes to any per-turn model rejection — entitlement mismatch, wrong model name, auth failure — not just this version gap.
Why it seems worth addressing
The failure is both silent and expensive to diagnose. The logs show clean completions, so the natural first suspects are the prompt, the ticket config, or agent behaviour — none of which are the cause. Surfacing the error (or treating a run of empty turns as blocked) would turn what was a multi-hour investigation into an immediate, obvious signal.
Suggested directions (either or both)
Surface codex/event/error above debug (e.g. warning), including the payload, so a rejected turn is visible in normal logs.
Treat consecutive empty turns as a blocked run — a task_complete with last_agent_message: null immediately following a codex/event/error, repeated — and stop / hand off rather than continuing to the cap.
All reactions