Skip to content

Hooks stop firing after rate-limit stops or live hooks.json edits #21160

Open

Description

@kawa0721

What variant of Codex are you using?

CLI / TUI

Which version are you using?

codex-cli 0.128.0

What operating system are you using?

  • Ubuntu 24.04 LTS on WSL2
  • Kernel: 6.6.87.2-microsoft-standard-WSL2
  • Node: v22.22.0
  • npm: 11.12.1

Bug description

Hooks can stop firing in a live Codex session under two conditions:

  1. When Codex hits a rate limit and stops, the expected lifecycle hook does not appear to run.
  2. When hooks.json is edited while Codex is already running, hooks stop firing entirely for the remainder of that session.

This is more severe than hooks not hot-reloading. After a live hooks.json update, the session appears to lose hook execution altogether. The only reliable workaround I have found is to restart the Codex session.

The hook configuration file is valid JSON. In the affected workspace, the repo-local hook file exists at .codex/hooks.json, and jq validates it successfully.

Expected behavior

For rate-limit stops:

  • The appropriate stop/session lifecycle hook should still run when Codex stops because of a rate limit, or Codex should explicitly document and surface that hooks are skipped for that stop reason.
  • Hook-driven cleanup, logging, or continuation workflows should not fail silently.

For live hooks.json edits, one of these behaviors would be acceptable:

  • Keep using the previously loaded hook configuration until the session restarts.
  • Hot-reload the updated hook configuration safely.
  • Detect the change, report that hooks require a restart, and keep the previous working hook set active.

What should not happen is that all hooks silently stop firing for the rest of the live session.

Actual behavior

Observed behavior:

  • After a rate-limit stop, the stop-related hook does not appear to run.
  • After modifying hooks.json during an active session, no hooks appear to run again in that session, even though the resulting hooks.json remains valid JSON.
  • Restarting Codex/session restores hook behavior.

Steps to reproduce

Scenario A: rate-limit stop

  1. Configure a simple hook that produces a visible side effect, such as appending a timestamp to a temporary log file.
  2. Start a long-running Codex CLI/TUI session with hooks enabled.
  3. Continue working until Codex hits a rate limit and stops.
  4. Check whether the stop/session lifecycle hook ran.

Scenario B: live hooks.json edit

  1. Configure a simple hook that appends to a temporary log file on each relevant event.
  2. Start a Codex CLI/TUI session and verify the hook fires.
  3. Edit .codex/hooks.json while the session is still running. Keep the file syntactically valid.
  4. Continue the same session and trigger more hook events.
  5. Observe that hooks no longer fire until the Codex session is restarted.

Impact

This breaks long-running workflows that rely on hooks for:

  • cleanup after stop/session lifecycle events
  • logging and audit traces
  • user-defined guardrails
  • continuation or handoff generation when a run stops unexpectedly

The failure mode is particularly costly because it is silent. The user may assume the hook-based workflow is still active when it is not.

Related issues

Possibly related, but not the same failure mode:

This report is specifically about hooks becoming non-functional in an existing CLI/TUI session after a rate-limit stop or after editing hooks.json during the live session.

Additional notes

A robust fix could be either:

  • keep the previous validated hook registry active until restart,
  • hot-reload hooks transactionally only after successful validation,
  • or surface a clear warning/error when hooks are disabled or skipped.

Activity

  1. added
    bugSomething isn't working
    CLIIssues related to the Codex CLI
    hooksIssues related to event hooks
    rate-limitsIssues related to rate limits, quotas, and token usage reporting
    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal display
    on May 5, 2026
  2. removed
    TUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal display
    CLIIssues related to the Codex CLI
    on May 5, 2026
  3. oxysoft commented on May 8, 2026

    @oxysoft

    Indexed this hook ticket in the umbrella tracker: #21753

    Goal: collect the scattered Codex hook requests and bugs into one parity matrix for Full Claude Code Hook Parity (29+), while preserving this issue as the detailed thread for its specific behavior.

  4. kc961163 commented on Aug 27, 2026

    @kc961163

    Additional reproduction from Codex Desktop and CLI:

    • Environment: macOS, codex-cli 0.150.0-alpha.8, signed in with ChatGPT.
    • In a long-lived Codex Desktop task, after the user-level hooks.json changed, the task continued recording successful task_started / task_complete events, but no further hook events were recorded and the hook's local side-effect state stopped changing. New prompts did not invoke UserPromptSubmit or Stop.
    • The same hook command succeeds when invoked directly. A fresh codex exec task also invoked SessionStart and UserPromptSubmit, which isolates the failure to hook dispatch in the existing Desktop task rather than the hook command itself.
    • The fresh CLI task then hit the ChatGPT usage limit before model execution. Stop did not run, leaving the observed turn without a terminal lifecycle event.

    This appears to expose two producer-side gaps:

    1. A live hook configuration change can leave an existing Desktop task running without dispatching subsequent hooks.
    2. Quota/provider termination can occur after UserPromptSubmit without a corresponding Stop or error lifecycle hook.

    Authentication does not appear to explain the first gap: Codex authentication selects ChatGPT subscription access or API-key usage-based access, while hooks are executed locally by the Codex client. I reproduced ChatGPT authentication only, not API-key mode. A successful fresh API-key task should use the same local hook dispatcher, while an API quota/provider failure may have the same missing-terminal-event risk described in #22774.

    Expected behavior: retain the previously validated hook registry until restart or reload it atomically; surface when hooks become inactive; and dispatch Stop or a dedicated error event for quota/provider termination.

  5. kc961163 commented on Oct 12, 2026

    @kc961163

    Still reproduces on a newer build, with a cleaner signal: the turn is recorded as complete, but Stop never runs.

    • Environment: macOS, codex-cli 0.162.0-alpha.17.2 (bundled with the desktop app), ChatGPT sign-in, user-level hooks.json with PreToolUse, PostToolUse, UserPromptSubmit and Stop command hooks (all trusted).
    • Ran codex exec with a prompt that makes 25 separate shell tool calls. After 22 of them the CLI printed ERROR: Selected model is at capacity. Please try a different model. and exited.
    • The rollout file for that turn has task_started, 22 tool calls, then task_complete.
    • PostToolUse ran for all 22 tool calls. Stop did not run: our hook deletes its per-turn state file in Stop, and that file is still on disk with no pending tools.
    • The same prompt with -m set to a model that had capacity completed all 25 calls, and Stop ran normally.

    So when a provider error ends a turn, the turn still gets task_complete, but neither Stop nor any error hook runs, and a hook that finalizes per-turn work on Stop can't tell the turn ended. Same gap as point 2 in my earlier comment, and what #22774 asks for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghooksIssues related to event hooksrate-limitsIssues related to rate limits, quotas, and token usage reporting

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions