708.9M session-token loop (701.0M cached): Desktop /goal unbounded identical retries when blocked-state recording fails

Open 💬 3 comments Opened Aug 1, 2026 by daveladouceur
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

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

  1. Start a persistent /goal in Codex Desktop.
  2. Configure a deterministic pre-tool hook failure that rejects every tool call.
  3. Let the agent determine that the goal is blocked and call:

``json
{"status":"blocked"}
``

  1. Observe that update_goal is itself rejected by the hook.
  2. Leave the task unattended.
  3. Observe repeated automatic continuation turns, each attempting the same state transition against unchanged state.
  4. 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_goal calls: 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.

  1. An identical call against an unchanged deterministic failure may be repeated once for confirmation, then must circuit-break.
  2. 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.
  1. Three attempts must mean three complete diagnose–repair–verify cycles—not three identical calls, much less thousands.
  2. If update_goal(blocked) itself fails, Desktop must record a local suspended/blocked state out-of-band and stop scheduling continuations.
  3. The task should surface one user-visible incident with the exact failure signature and required recovery action.
  4. 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 suspended state 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.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 26 days ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #36273

Powered by Codex Action

daveladouceur · 26 days ago

Additional impact: the goal must now be restarted

After repairing the hook and inspecting the task state, get_goal returns no active goal. The user therefore has to restart the full operating-platform goal rather than resume it.

The runaway session ended with approximately:

  • 708,895,754 total session/model-traffic tokens
  • 701,007,104 cached input tokens
  • 265,905 output tokens
  • 34,928 reasoning-output tokens
  • at least 7,401,726 post-failure goal tokens attributable to the deterministic continuation loop

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:

  1. The original persistent goal was stopped to terminate the loop.
  2. The goal record is now absent rather than resumable.
  3. Useful design work produced during the session exists only in the transcript.
  4. The source design document was not updated.
  5. No canonical plan, epic, child work items, migrations, graph database, implementation commits, or runtime acceptance evidence were created.
  6. A replacement goal must reconstruct the transcript-only design, persist it canonically, recreate governance state, and restart implementation from Wave 0.

This strengthens the need for an out-of-band runtime suspended state. A user should be able to stop runaway inference without losing the resumable goal record or forcing reconstruction of accumulated design state.

daveladouceur · 25 days ago

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