Repository navigation
MCP re-init loop on Stop-hook path hangs codex exec until timeout when an MCP server fails to start (effort-correlated) #32148
Description
What version of Codex CLI is running?
codex-cli 0.144.1
What subscription do you have?
ChatGPT (auth_mode: Chatgpt)
Which model were you using?
gpt-5.6-sol (also reproduces model-agnostically; the trigger is reasoning effort, not the model)
What platform is your computer?
Windows 11 Pro 10.0.26200 (running under Git Bash / MSYS). Node v24.13.1.
What issue are you seeing?
When a Stop hook is registered and at least one configured MCP server fails to start (e.g. a stdio server that exits non-zero at launch, or an HTTP server that needs auth), running codex exec with -c model_reasoning_effort=ultra causes Codex to hang after the model response is already printed. The model answers correctly, then Codex spins in a MCP re-initialization retry loop during shutdown and never exits — it is only killed by an external timeout (exit 124).
The observable surface is a burst of hook: Stop / hook: Stop Failed lines, but the hook scripts are not the cause (see isolation below). The real loop is Codex re-initializing the entire MCP manager on the Stop-hook path and retrying the failing server(s) indefinitely.
With RUST_LOG=info, the shutdown phase repeats this sequence dozens of times:
hook: Stop
...
WARN codex_mcp::rmcp_client: failed to initialize MCP client during shutdown:
MCP startup failed: handshaking with MCP server failed:
JSON-RPC error: -32600: Vault directory does not exist: c:/jexer/vault
WARN codex_mcp::rmcp_client: failed to initialize MCP client during shutdown:
... Auth required, when send initialize request
app_server.request{... thread/start ...}: session_init.mcp_manager_init: ...
rmcp::transport::child_process: Child exited gracefully exit code: 1
rmcp::service: input stream terminated ... serve finished quit_reason=Closed
thread/start → session_init.mcp_manager_init fires 50+ times and Child exited exit code: 1 8–9 times in a single codex exec shutdown.
Reproduction
- Register any Stop hook (content is irrelevant — even a script that immediately
exit(0)triggers it). - Have at least one configured MCP server that fails at startup. Two real examples we hit:
- stdio:
npx -y obsidian-mcp c:/jexer/vaultwhere the vault dir does not exist →Error: Vault directory does not exist. - HTTP:
https://mcp.figma.com/mcpwhile not logged in →Auth required.
- stdio:
- Run with high reasoning effort so the turn takes a while:
timeout 70 codex exec -m gpt-5.6-sol -c model_reasoning_effort=ultra \
-s read-only "Reply with exactly: PONG-ULTRA"Result: PONG-ULTRA prints, then the Stop-hook / MCP-reinit loop runs until the 70s timeout → exit 124. With a short/medium turn the loop sometimes finishes before the timeout, so the failure is intermittent and effort-correlated.
Isolation (what is and isn't the cause)
Three controlled runs, using exited gracefully exit code: 1 count as the loop indicator:
| Change | loop count | conclusion |
|---|---|---|
| Disable the plugin providing the Stop hooks (no Stop hook) | 0 | a registered Stop hook is the trigger |
Keep Stop hooks, replace the hook scripts with process.exit(0) stubs |
9 | hook script content / any subprocess it spawns is not the cause |
| Keep Stop hooks, create the missing vault dir (fix one failing MCP) | 8 (only the auth one remains) | it's the failing MCP, and each failing server contributes |
Removing the failing MCP servers eliminates the loop entirely (verified: 4/4 ultra runs exit 0, zero Vault directory / Auth required in logs).
Cross-agent control
We ran the same failing stdio MCP under a different harness (Claude Code, --mcp-config with a stub that exits 1 at startup, same Stop hooks firing). It logged the identical startup failure (Connection failed ... MCP error -32000) but did not retry — it failed once and exited 0 in ~33s. So this is specific to how Codex re-initializes the MCP manager on the Stop-hook / shutdown path, not a generic MCP-startup problem.
Expected behavior
A failing MCP server should fail once (or with bounded retries) and must not block session/process termination. The Stop-hook path should not re-initialize the whole MCP manager and retry unhealthy servers unboundedly. codex exec should exit promptly after the model response regardless of a dead MCP server or reasoning effort.
Activity
4fkdgoa commentedon Jul 10, 2026
Closing this as not-a-bug / withdrawn by reporter after further verification.
I re-examined the original full logs (not the grep excerpts I first worked from) and ran a peer review, and the causal claims in this report do not hold up:
Child exited gracefully exit code: 1and thethread/startrepetitions are NOT a failing-MCP retry loop. They are Codex's normal shutdown logging. With zero failing MCP servers (both the missing-vault stdio server and the unauthenticated HTTP server removed), the same run still showsexit code: 1×8 andthread/start×54 — identical to the run that still had a failing server. So the count is independent of whether any MCP fails.thread/startlines are all the same span (request_id=1) repeated as a log prefix, not 50+ distinct re-initializations. My "re-initializes the whole MCP manager and retries unboundedly" reading was a misread of the trace prefix.Connection failed ... MCP error -32000), not in an unbounded loop.exit 124symptom is not actually captured in the evidence I based the conclusion on.The only thing I can still substantiate is that Codex's shutdown path appears to block on MCP client teardown where another client did not — which may be worth looking at, but that is a much weaker and different statement than what this issue asserts. Rather than leave an inaccurate report open, I'm withdrawing it. Apologies for the noise, and thanks.