708.9M session-token loop (701.0M cached): Desktop /goal unbounded identical retries when blocked-state recording fails
What version of Codex are you using?
- Product: Codex Desktop on Windows
- Codex CLI:
0.146.0-alpha.3.1 - Model:
gpt-5.6-sol, medium reasoning - Goal mode with automatic continuation
- Approval policy: never
- Filesystem sandbox: danger-full-access
- Observed: 2026-08-01
Summary
A persistent /goal entered an effectively unbounded automatic-continuation loop after a deterministic PreToolUse hook failure blocked all tools—including the update_goal(status: "blocked") call intended to stop the goal.
Instead of suspending locally after the blocked-state transition failed, Desktop scheduled another automatic continuation. The next turn made the same update_goal call, received the same hook failure, and scheduled another continuation. This repeated 2,514 attempted update_goal calls until I manually sent stop.
The agent had instructions that should have constrained this behavior:
- non-destructive, in-scope repairs were authorized;
- a blocked audit required three consecutive goal turns before marking the goal blocked;
- the retry/refactor policy meant three complete diagnose–repair–verify cycles, not three identical calls.
However, once the pre-tool hook prevented both repair tools and the goal-state tool from running, there was no runtime circuit breaker or out-of-band way to suspend the goal. The policy text could not prevent the continuation scheduler from repeatedly re-entering the same deterministic failure.
Trigger
A JavaScript pre-tool hook was loaded as CommonJS even though its package scope declared ESM:
.../codex/hooks/require-codeflow-up.js:31
const http = require('node:http');
^
ReferenceError: require is not defined in ES module scope
Every tool call was rejected by the pre-tool hook before execution. The first affected call was an ordinary connector operation; subsequent calls attempted to record the goal as blocked.
The local hook was later repaired externally. The edit itself was small and non-destructive. The central Codex bug is not the hook error: it is that a failed blocked-state transition caused thousands of identical automatic continuation turns.
Reproduction outline
- Start a persistent
/goalin Codex Desktop. - Configure a deterministic pre-tool hook failure that rejects every tool call.
- Let the agent determine that the goal is blocked and call:
``json``
{"status":"blocked"}
- Observe that
update_goalis itself rejected by the hook. - Leave the task unattended.
- Observe repeated automatic continuation turns, each attempting the same state transition against unchanged state.
- The loop stops only when the user manually sends
stop, an external limit intervenes, or the hook is repaired outside the task.
Actual behavior and measured impact
Sanitized evidence from the local structured session transcript:
- First pre-tool hook failure:
2026-08-01T08:24:56.811Z - First attempted blocked-state update:
2026-08-01T08:26:38.631Z - Last repeated update before manual stop:
2026-08-01T16:36:31.089Z - Manual
stop:2026-08-01T16:36:41.793Z - Runaway duration: approximately 8 hours 11 minutes 45 seconds
- Attempted
update_goalcalls: 2,514 - Recorded pre-tool hook failures: 2,521 (including the initial non-goal tool failures)
- Goal token counter after the failure became visible:
463,901 - Final goal token counter before stop:
7,865,627 - Conservative post-failure goal-token waste: at least 7,401,726 tokens
The session-level model traffic counter reached approximately 708.9 million tokens, overwhelmingly cached repeated context. That is not presented as billed usage; it shows the scale of redundant model/session traffic produced by the loop.
I am not attaching the raw transcript because it can contain local paths and credentials. The counts above were derived from exact structured events.
Expected behavior
A deterministic tool or hook failure must not produce an unlimited automatic-goal loop.
- An identical call against an unchanged deterministic failure may be repeated once for confirmation, then must circuit-break.
- A retry allowance must count complete repair cycles:
- diagnose from new evidence;
- apply a materially different authorized repair;
- verify against the original failing action;
- record the outcome.
- Three attempts must mean three complete diagnose–repair–verify cycles—not three identical calls, much less thousands.
- If
update_goal(blocked)itself fails, Desktop must record a local suspended/blocked state out-of-band and stop scheduling continuations. - The task should surface one user-visible incident with the exact failure signature and required recovery action.
- Automatic continuation should resume only after an explicit user action or a detected external-state change.
Proposed runtime safeguards
- Hash/deduplicate failure signatures using tool name, hook name, error class, normalized message, and relevant state version.
- Stop identical retries after two occurrences with no state change.
- Maintain a repair-cycle journal: diagnosis, mutation, verification, result.
- Add a runtime-owned
suspendedstate that does not depend on model tool execution. - If the model cannot persist
blocked, have the goal runner fail closed instead of treating the goal as still active. - Expose in Desktop:
- continuation count;
- current repair-cycle number;
- last failure signature;
- mutations and verification evidence;
- tokens used since the failure began;
- user-settable maximum repair cycles;
- Pause and Stop controls.
- Consider a narrowly scoped, audited recovery channel for trusted non-destructive repairs to a broken local hook/configuration when that same hook blocks ordinary tool execution.
Acceptance criteria
- A regression test makes
update_goal(blocked)fail deterministically through a pre-tool hook. - No more than one confirmation retry occurs for the unchanged failure signature.
- The goal becomes runtime-suspended without requiring the failed tool.
- No further automatic continuation is scheduled until explicit resume or a relevant external-state change.
- The UI clearly explains the suspension and shows the failure signature and token impact.
- Tests distinguish identical retries from full repair cycles.
Related issue checked
- #28923 reports a different unbounded continuation case involving future-time waits. This report concerns a deterministic tool/hook failure where the goal's own blocked-state transition is intercepted, creating a control-plane feedback loop.
3 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Additional impact: the goal must now be restarted
After repairing the hook and inspecting the task state,
get_goalreturns no active goal. The user therefore has to restart the full operating-platform goal rather than resume it.The runaway session ended with approximately:
The 708.9M figure is session/model traffic, not a claim about billed usage. The 7.4M goal-token delta is the conservative direct waste measurement from the goal counter after the hook failure became visible.
The recovery cost is larger than token consumption alone:
This strengthens the need for an out-of-band runtime
suspendedstate. A user should be able to stop runaway inference without losing the resumable goal record or forcing reconstruction of accumulated design state.Created another test .... Codex - Spark 5.3 -- ate 1 week in 3.5 hours -- this was GOAL based no inputs
My apology cannot grab the data as locked out of all of Codex and Open AI
Token usage: total=9,469,686 input=8,416,873 (+ 183,934,336 cached) output=1,052,813 (reasoning 638,114)
To continue this session, run codex resume 019fc42f-e008-79e2-9d11-b7a5b2eb7f43
Task Create 50 E2E tests for web editor
4 Hours 100% Weekly allowance done