Repository navigation
Goal ignores an explicit human-hours pause and burns 1.26M tokens in 12 no-op turns #41831
Description
What version of Codex are you using?
Codex Desktop with connected codex-cli 0.150.1 runtime.
Model: gpt-5.6-sol, xhigh reasoning.
What platform are you using?
Nobara Linux 44, x86_64, kernel 7.2.0-202.nobara.fc44.x86_64.
When did this happen?
2026-08-31 in America/Sao_Paulo (UTC-03:00).
- Session started: 08:29:14 local / 11:29:14 UTC
- Goal created: 08:35:31 local / 11:35:31 UTC
- Main work turn completed: 09:08:50 local / 12:08:50 UTC
- Repeated continuation window: 09:08:50–09:10:33 local / 12:08:50–12:10:33 UTC
- Goal status finally changed to
paused: 09:10:28 local / 12:10:28 UTC
What happened?
I gave Codex a 737-line execution handoff for a private, multi-day implementation. The project context is intentionally anonymized, but the relevant handoff structure was:
- eight ordered phases (0–7), with Phase 0 explicitly read-only;
- research, correctness, compatibility, build, QA, worklog, and publication gates;
- a resume capsule, evidence ledger, and worklog for cross-session state;
- a maximum of 8 human-equivalent work hours per Monday–Friday day and 40 hours per week;
- closeout counted inside the 8-hour cap, weekends with zero planned capacity, and unfinished work deferred to the next weekday;
- an explicit requirement to stop working and pause when the human-equivalent capacity limit was reached;
- remote publication prohibited until a late final-phase gate.
During the first work turn, I sent this additional instruction:
Set a Goal whose objective is completing this implementation, and always pause it when the human-time limit is exceeded.
Codex created an active Goal whose objective included completing all phases and gates while performing closeout and stopping at the 8-hour/40-hour human-equivalent limits.
When its worklog reached 8/8 human-equivalent hours for the day, Codex performed closeout and ended the main turn with a clear terminal response saying execution was paused until the next real weekday. The implementation was incomplete, so the Goal correctly was not marked complete. It also was not blocked.
However, the persisted Goal was still active. Only 79 ms after the main task_complete, the Goal continuation hook started a new turn and injected:
<codex_internal_context source="goal">
Continue working toward the active thread goal.
...
Tokens remaining: unbounded
...
Do not call update_goal unless the goal is complete or the strict blocked audit above is satisfied.
</codex_internal_context>
The assistant honored the handoff and responded that no work could occur because the 8/8-hour human-equivalent limit had been reached. As soon as each no-op turn completed, the hook immediately started another one. This repeated 12 times without user input or project work.
The loop stopped only after the persisted Goal status changed to paused. The rollout does not show an agent tool call that caused that status transition.
Sanitized event sequence
09:08:50.589 task_complete # main work turn and daily closeout
09:08:50.668 task_started # automatic continuation, +79 ms
09:08:51.263 internal goal continuation injected
09:09:01.955 assistant: goal remains active, execution paused until next weekday
09:09:02.071 task_complete
09:09:02.108 task_started # automatic continuation again, +37 ms
...
09:10:26.791 task_started # 12th automatic continuation
09:10:27.373 internal goal continuation injected
09:10:28.168 thread_goal_updated status=paused
09:10:33.395 task_complete
Total repeated-continuation duration: about 1 minute 43 seconds.
Token impact
These are recorded runtime counters, not a billing estimate:
| Counter | Before loop | After loop | Increase |
|---|---|---|---|
total_token_usage.total_tokens |
10,485,436 | 11,751,024 | 1,265,588 |
| Input tokens | 10,447,054 | 11,711,643 | 1,264,589 |
| Cached input tokens | 9,998,080 | 11,240,704 | 1,242,624 |
| Output tokens | 38,382 | 39,381 | 999 |
Goal tokensUsed |
384,976 | 406,034 | 21,058 |
Each automatic no-op turn recorded roughly 98,772–112,114 total tokens because the same large context was reprocessed. Most were cached input, but the rollout's total token counter still increased by 1.26M and the Goal counter also increased.
Why the Goal contract could not honor the request
The agent-facing Goal lifecycle creates an active Goal, while the available update_goal operation only permits complete or blocked. It does not expose paused, waiting, or a wake time. The injected continuation context also explicitly forbids using blocked for an ordinary pause.
That leaves no valid agent action for this requested state:
Goal incomplete
+ daily human-equivalent capacity exhausted
+ preserve Goal for the next weekday
+ perform no more model turns until then
The assistant can say it is paused, but the scheduler still sees an active Goal and immediately requeues it.
Expected behavior
- An explicit pause/stop condition inside the Goal objective must be able to persist a non-continuing state.
- The agent should be able to set
pausedorwaiting, ideally with an optionalwakeAttimestamp. - The scheduler should re-check Goal state before enqueueing and before injecting a continuation.
- Queued or in-flight continuation leases should be discarded after a pause.
- Repeated semantically identical no-progress responses should trigger deduplication, backoff, and a low continuation/usage circuit breaker.
- A time-based wait should not require misclassifying a healthy Goal as
blocked. - The UI should expose that execution is paused while preserving the incomplete Goal.
Related issues
- Goal auto-continuation can enter an unbounded no-progress loop and generate thousands of duplicate turns #34248 reports the same unbounded no-progress continuation class at much larger scale. This report adds a compact reproduction where the Goal objective itself contains an explicit human-hours stop gate.
- Add wait/wake support for goals without spending tokens #28144 requests durable wait/wake support without token usage, which would provide the missing lifecycle state here.
The full rollout contains private workspace details and is not suitable for public attachment. I can provide targeted sanitized event excerpts privately if needed.
Activity
github-actions commentedon Aug 31, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Kizuno18 commentedon Sep 1, 2026
Follow-up: reproduced again the next day in the same private thread
This happened again on 2026-09-01 in
America/Sao_Paulo(UTC-03:00), with a much larger impact.The user explicitly resumed the next day's work at 07:18:32 local. The persisted Goal became
activeat 07:37:35. A legitimate work turn then ran and completed its first-phase closeout at 08:30:41.925 local. Its terminal response explicitly said the daily 8/8 human-equivalent hours had been reached, execution was paused until the next weekday, and the incomplete Goal would remain available for the following phase.The continuation scheduler started another turn 181 ms later, despite that terminal condition. No human input occurred during the resulting loop.
Second-loop timeline
Equivalent UTC window: 11:30:41.925–13:23:03.898 UTC.
Observed duration: 1h 52m 21.792s.
Loop shape
<codex_internal_context source="goal">Continue working toward the active thread goal...</codex_internal_context>messagespausado até o próximo dia útilafter trimming whitespaceThe loop stopped only because the provider rate limit reached 100%. The durable Goal row then became
usage_limited, notpaused.Token-counter impact
These are source-scoped cumulative runtime counters from one monotonic epoch, not a billing total or cost estimate:
total_token_usage.total_tokensThe Goal's own
tokensUsedvalue embedded in continuation contexts rose from 899,306 on the first no-op continuation to 3,915,956 on the final one: an increase of 3,016,650.Per-turn
last_token_usage.total_tokensalso grew from 54,868 on the first automatic no-op turn to 200,205 on the final completed one. This shows a context-amplification loop: every duplicate turn enlarged the history that the next duplicate turn processed.Direct tool-contract evidence
On the fourth automatic continuation, the assistant inspected every available tool whose name or description matched
goal|pause.The only relevant controls were:
create_goalget_goalupdate_goalThe exposed
update_goalschema allowed only:Its description explicitly said:
The Goal was incomplete and not genuinely blocked, so the agent had no valid state transition that could honor the Goal's explicit daily pause condition. Saying “paused” in the final answer had no scheduler effect.
This second reproduction makes the missing safety boundary clearer: a no-progress Goal can continue at sub-second cadence until quota exhaustion, while its ever-growing history makes each duplicate turn progressively more expensive.
Suggested regression test:
cyberianin commentedon Oct 7, 2026
Environment: Windows 10 LTSC 21H2, Codex App 26.1002.6548.0 (
OpenAI.Codex_26.1002.6548.0_x64__2p2nqsd0c76g0).Reproduced on October 7, 2026 with an active long-running Goal.
I can still reproduce this class of failure with an explicit deferred pause instruction in an active long-running Goal.
The important difference from an immediate “pause now” request is that I asked Codex to finish one bounded piece of work, produce its report, and then stop before returning to the larger Goal.
My instruction was effectively:
Codex completed the requested batch and replied with the commit SHA and report. Its response explicitly said:
At that point the requested stopping condition had been reached exactly.
However, the Goal remained active. After the turn completed, an automatic Goal continuation started and Codex immediately resumed work on the larger objective:
It then started running additional commands and measurements without any new user instruction.
So in this reproduction, the model appears to have understood the user-level instruction correctly: it completed the bounded batch, produced the requested report, and explicitly acknowledged that it would not proceed further. The failure appears at the Goal lifecycle boundary: completing that turn did not transition the persisted Goal out of
active, so the automatic continuation scheduler resumed the larger objective.This is particularly problematic for long-running Goals composed of multiple stages. A user needs to be able to say “finish this subtask, checkpoint/report, then stop” without having to expose or know an internal lifecycle API such as
update_goal(status="paused").Expected behavior: an explicit deferred stop/pause condition in a user message should become a Goal lifecycle boundary. Once the requested bounded work and report are complete, the Goal should enter
pausedand no autonomous continuation should be scheduled until the user explicitly resumes it.This looks closely related to #46904, but that report covers an immediate natural-language pause. This reproduction covers a deferred pause after a finite subtask/checkpoint, which is an important workflow for multi-stage Goals.