Skip to content

A repeatedly blocking Stop hook can trap Codex CLI in an infinite no-escape loop #37937

Description

@jyongchul

What version of Codex are you using?

codex-cli 0.147.0

What subscription do you have?

ChatGPT paid subscription with multiple local CODEX_HOME profiles.

What model were you using?

gpt-5.6-sol (the failure is in local hook control flow and appears model-independent).

What platform are you using?

Linux 7.0.0-28-generic x86_64 unknown, reached from Windows Terminal over SSH, with Codex running in long-lived tmux sessions.

What issue are you seeing?

A long-running Codex CLI session can become trapped in an effectively infinite loop when its Stop command hook repeatedly returns a blocking result after an external runtime dependency becomes invalid.

In the observed case, the exact versioned hook launcher file was still present and executable. The failure occurred deeper in the hook: a shared configuration source had moved to a newer runtime checkout while the live session still used an older launcher generation. The hook could no longer resolve a compatible runtime candidate and returned the same blocking feedback on every invocation:

Stop hook (blocked)
feedback: Multi Server Sync Hook Router was not found; run gateway-service.py ensure or set MULTI_SERVER_SYNC_ROOT

When the assistant tried to finish after reporting the failure, Codex invoked Stop again. The hook returned the identical block, its feedback caused another model turn, and the next attempt to finish invoked the same failing hook again. The loop did not converge or return stable control to the user. Multiple long-running sessions exposed the same pattern.

This is not a missing hook executable in the current reproduction. It is a hook dependency/infrastructure failure that Codex treats like a fresh intentional policy block indefinitely. Manual process termination or session restart stops the loop, but restarting a long-running stateful session loses continuity and should not be the only escape path.

Steps to reproduce

  1. Configure a command Stop hook that normally permits completion but depends on runtime or configuration state outside the Codex process.
  2. Start Codex CLI and keep the session running.
  3. Change that external dependency so the hook launcher still exists and runs, but it returns the same blocking error on every Stop event.
  4. Ask Codex to complete the turn.
  5. Observe that the blocked-hook feedback produces another model turn.
  6. Observe that every subsequent attempt to finish invokes Stop again, receives the same block, and continues without a bounded retry limit or user-visible escape.

Expected behavior

A Stop hook may intentionally block one stop attempt, but Codex must not create an unbounded automatic loop when the same hook returns the same block repeatedly without new user input or measurable progress.

At minimum, Codex should:

  • detect and suppress identical consecutive Stop blocks after a small bounded number of attempts;
  • pause and return control to the user instead of automatically starting another model turn;
  • distinguish hook execution/infrastructure failures from deliberate policy denials; and
  • provide a safe, explicit escape path that ends the current turn while clearly reporting whether a hook was bypassed.

If a deployment chooses fail-closed behavior for hook failures, it should fail closed once and wait for user action, not consume unbounded model turns and tokens.

Additional information

Live verification confirmed that the historical versioned hook-router.py path still existed. The router failed later because its shared configuration source selected a newer runtime checkout that did not match the live launcher generation, leaving no compatible candidate root. This distinction matters: restoring a missing plugin cache path is not the applicable fix for this incident.

Related reports:

  • #34477 covers an infinite loop caused by hook-injected <hook_prompt> messages. This report reproduces the same unbounded-stop safety gap from a different trigger: repeated blocking feedback caused by an invalid external hook dependency.
  • #31383 covers running sessions retaining hook commands under plugin cache directories that were deleted. Here the exact hook launcher remained present.
  • #25285 concerns Windows Codex Desktop and stale hashed skill paths, not Linux CLI Stop hook control flow.

We are intentionally omitting customer data, account identifiers, IP addresses, credentials, and private session screenshots. We can provide a sanitized diagnostic bundle or test a candidate fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workinghooksIssues related to event hooks

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions