Summary
When a native Codex bash call hangs and is reaped as a synthetic missing_tool_result (the #86808 fail-closed path), OpenClaw's model-fallback engine classifies it as unclassified and fails over to the next configured provider (e.g. openai/gpt-5.4 → anthropic/claude-opus-4-8). A hung local shell command is not a model/provider fault, so failover cannot remedy it — it just silently switches the user's model mid-conversation. The 5-minute auto-override probe then reverts to primary, and the next long command repeats the cycle, producing visible provider "jumping."
Version
2026.5.28 (e932160). Model/routing: openai/gpt-5.4 (Codex OAuth), fallback anthropic/claude-opus-4-8.
Steps to reproduce
- Run a Codex-backed agent turn that issues a long-running / non-terminating shell command (e.g. a heavy parallel test suite).
- The native
bash call never returns a result and is reaped at turn finalization as missing_tool_result.
- Observe
session.ended status=error, then model fallback decision: decision=candidate_failed requested=openai/gpt-5.4 … next=anthropic/claude-opus-4-8.
Expected behavior
A local tool-execution failure (missing_tool_result; denied/timed-out/orphaned tool call) should be surfaced to the user and/or retried on the same model. It should be non-failover-eligible — no other provider can fix a local command, so it must not advance agents.defaults.model.fallbacks.
Actual behavior
missing_tool_result is classified unclassified, which the failover policy treats as "other unrecognized error with remaining candidates" → cross-provider model fallback fires. Each new turn re-requests the primary, the 5-minute probe clears the override, and the cycle repeats — the user sees the model bounce between providers with no credit/rate-limit cause.
Evidence
Two turns ~17 min apart, identical signature (model.completed fired; not a missing turn/completed as in #88312):
tool.call bash id=…Fte1QSBG ("bun run test" in a local repo) @ T+0
…dozens of other bash calls complete normally…
tool.result bash id=…Fte1QSBG status=failed reason=missing_tool_result @ ~T+15min
model.completed
session.ended status=error
→ model fallback decision: candidate_failed requested=openai/gpt-5.4 next=anthropic/claude-opus-4-8
Codex app-server logged only codex_analytics::reducer: dropping turn tool count update: missing turn state … item_id=call_…Fte1QSBG for the hung call; no tool.result was ever produced.
Proposed fix
Add missing_tool_result / local-tool-execution failures to the non-failover classification set (alongside existing carve-outs) so they do not trigger model fallback. Optionally pair with a per-tool execution timeout so hung native shell commands fail fast with a real terminal result instead of stalling the whole turn.
Related
Summary
When a native Codex
bashcall hangs and is reaped as a syntheticmissing_tool_result(the #86808 fail-closed path), OpenClaw's model-fallback engine classifies it asunclassifiedand fails over to the next configured provider (e.g.openai/gpt-5.4→anthropic/claude-opus-4-8). A hung local shell command is not a model/provider fault, so failover cannot remedy it — it just silently switches the user's model mid-conversation. The 5-minute auto-override probe then reverts to primary, and the next long command repeats the cycle, producing visible provider "jumping."Version
2026.5.28 (e932160). Model/routing:openai/gpt-5.4(Codex OAuth), fallbackanthropic/claude-opus-4-8.Steps to reproduce
bashcall never returns a result and is reaped at turn finalization asmissing_tool_result.session.ended status=error, thenmodel fallback decision: decision=candidate_failed requested=openai/gpt-5.4 … next=anthropic/claude-opus-4-8.Expected behavior
A local tool-execution failure (
missing_tool_result; denied/timed-out/orphaned tool call) should be surfaced to the user and/or retried on the same model. It should be non-failover-eligible — no other provider can fix a local command, so it must not advanceagents.defaults.model.fallbacks.Actual behavior
missing_tool_resultis classifiedunclassified, which the failover policy treats as "other unrecognized error with remaining candidates" → cross-provider model fallback fires. Each new turn re-requests the primary, the 5-minute probe clears the override, and the cycle repeats — the user sees the model bounce between providers with no credit/rate-limit cause.Evidence
Two turns ~17 min apart, identical signature (
model.completedfired; not a missingturn/completedas in #88312):Codex app-server logged only
codex_analytics::reducer: dropping turn tool count update: missing turn state … item_id=call_…Fte1QSBGfor the hung call; notool.resultwas ever produced.Proposed fix
Add
missing_tool_result/ local-tool-execution failures to the non-failover classification set (alongside existing carve-outs) so they do not trigger model fallback. Optionally pair with a per-tool execution timeout so hung native shell commands fail fast with a real terminal result instead of stalling the whole turn.Related
tool.callwithout a matchingtool.resultwhen a Codex turn is denied, interrupted, or terminated #86808 (closed) introduced themissing_tool_resultsynthetic-result behavior — correct, but its interaction with model-fallback classification is unhandled.