Skip to content

Native hook relay starves mid-turn after long model-thinking gap (renewal loop tool-call-driven) #89147

Description

@scipher888

Native hook relay drops mid-agent-turn after long model-thinking gaps

Filed against: OpenClaw 2026.5.28 (commit e932160)
Reporter date: 2026-05-27
Retest / submission update: 2026-06-01
Severity: Medium — recoverable per-turn but disrupts long agent runs; affects all Codex (GPT-5) sessions that include >~90s thinking gaps mid-turn.

Environment

  • OpenClaw 2026.5.28 (commit e932160), installed via npm at /opt/homebrew/lib/node_modules/openclaw/; CLI and Gateway both verified on 2026.5.28 after gateway restart on 2026-06-01
  • macOS 26.5 arm64, node 25.5.0
  • Codex (GPT-5) agent running via ai.openclaw.gateway LaunchAgent
  • Gateway was freshly bootout+bootstrap-restarted at 2026-05-27 15:22 PT before the captured reproducer (rules out stale-process drift across the boundary)

Symptom

The Codex exec_command tool returns the literal string:

Command blocked by PreToolUse hook: Native hook relay unavailable.

mid-way through an agent turn that had previously executed successful tool calls on the same gateway PID. The same shell-style call (sed -n, rg, pwd) succeeds before the gap and fails after, with no intervening user action.

Reproducer

Rollout file:

/Users/synthiacipher/.openclaw/agents/main/agent/codex-home/sessions/2026/05/27/rollout-2026-05-27T16-31-43-019e6bc7-9987-74d0-97a9-0a7459da7a9f.jsonl

Timeline (UTC, single agent turn, gateway PID 41808 throughout):

Time (UTC) Δ Tool calls Result
23:32:08–23:32:17 8 reads (sed -n, rg) All exited with code 0
23:33:57 +100s (model thinking) 4 reads (sed -n) All Native hook relay unavailable
23:35:46 +107s 1 read (pwd) Native hook relay unavailable

The 100-second model-thinking gap is the inflection point — every tool call after the gap fails until the agent yields, and the failure persists across additional thinking gaps inside the same turn.

Contradiction with documented constants

Per the shipped bundle at /opt/homebrew/lib/node_modules/openclaw/dist/:

  • CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4 → 30 minutes minimum TTL
  • CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4 → 60s renewal interval
  • MAX_NATIVE_HOOK_RELAY_INVOCATIONS = 200 → 200-call cap per bridge

A 100-second model-thinking gap should not exhaust any of these on its own. Hypothesis: the renewal pings are driven by the Codex app-server tool-call cadence and stop while the model is in long thinking, with no server-side keepalive timer. By the time the next tool call arrives, the bridge has either been GC'd or its state is stale, and the app-server surfaces the resulting "unavailable" verbatim to the model.

Other observations

  • openclaw hooks check reports Ready: 5 / Not ready: 0 both before and after the failure window, so that diagnostic doesn't detect this case — it tests registry, not in-flight bridges.
  • The bridge directory ~/.openclaw/tmp/openclaw-native-hook-relays-501/ is empty at idle, which appears to be normal lazy-init behavior; not the cause.
  • 12 distinct rollouts on 2026-05-27 alone contain this error or the agent's narrativized form of it ("the hook relay seems to have failed…"). This is not a one-off.
  • Gateway log (~/Library/Logs/openclaw/gateway.log) has no [hook]/[relay]/[bridge] entries around the failure window. The failure path is either logged only at DEBUG, or it lives in the Codex sidecar stream rather than the gateway's main log. Either way, the user-visible surface is the literal verbatim error inside the model's tool-call output, with no breadcrumb anywhere in the standard logs.

Reproduction status on 2026.5.28

Retested on 2026-06-01 after upgrading the CLI to OpenClaw 2026.5.28 (commit e932160). The running Gateway initially remained on 2026.5.27, which caused immediate agent-turn failures with:

GatewayClientRequestError: Error: Unable to resolve bundled plugin public surface speech-core/runtime-api.js

Restarting the Gateway aligned CLI and Gateway on 2026.5.28; the synthetic relay test was then run again.

Test protocol:

  • Prompt A (baseline, no injected keepalive): Think very carefully for at least 90 seconds about the tradeoffs between event-driven and timer-driven keepalive mechanisms in client/server bridges. Then run pwd.
  • Prompt B (keepalive injected): First run pwd. Then think very carefully for at least 90 seconds about the tradeoffs between event-driven and timer-driven keepalive mechanisms in client/server bridges. Then run pwd again.
  • Each prompt was run 3 times with a unique fresh session key, --thinking high, and --timeout 420.

Results:

Prompt Runs Result Durations
A baseline 3 3/3 final pwd succeeded; no Native hook relay unavailable string 91s, 47s, 65s
B keepalive 3 3/3 final pwd succeeded; no Native hook relay unavailable string 56s, 91s, 77s

Interpretation: the synthetic prompt did not reproduce the mid-turn relay failure on 2026.5.28. It also did not demonstrate that the no-op keepalive helps, because baseline did not fail. Only two of the six runs reached the requested ~90s duration, so this is best treated as inconclusive rather than proof of a fix.

Full raw experiment log:

~/.openclaw/logs/relay-keepalive-experiment-2026-06-01.md

Additional post-upgrade observation: each valid run included an earlier failed/timed-out internal attempt with:

Package subpath './plugin-sdk/codex-native-task-runtime' is not defined by "exports" in /Users/synthiacipher/.openclaw/npm/node_modules/@openclaw/codex/node_modules/openclaw/package.json imported from /Users/synthiacipher/.openclaw/npm/node_modules/@openclaw/codex/dist/run-attempt-BqRPAaHk.js

OpenClaw retried and produced a successful final answer, so this appears separate from the native-hook-relay failure but may indicate a package export mismatch in the bundled Codex runtime.

Related

Suggested fix area

The likely fix area is a server-side keepalive timer independent of tool-call cadence. The relay should be renewed every CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS / NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS by wall clock while the turn is active, regardless of whether the model is currently issuing tool calls. That would prevent long model-thinking gaps from starving relay renewal and would keep the app-server from surfacing a low-level bridge availability error as a tool result.

Suggested fixes (for upstream to consider)

  1. Server-side keepalive timer. Renew the relay bridge independently of app-server tool-call cadence, so model-thinking gaps don't starve the renewal loop.
  2. Granular INFO logging on relay failure. When the relay returns "unavailable," log which specific condition tripped — bridge expired vs bridge not found vs unreadable result vs renewal-window missed — at INFO so users can self-diagnose without grepping dist/.
  3. App-server side: re-spawn the bridge before surfacing failure. On Native hook relay unavailable, have the Codex app-server transparently re-spawn the bridge and retry once, since the model has no useful recovery action and currently confabulates an explanation instead.
  4. (Optional) Surface relay state in openclaw hooks check. Extend the diagnostic to inspect in-flight bridge state and TTL, not just registry readiness, so the check matches what users assume it covers.

How I'd reproduce

  1. Start a fresh gateway: launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/ai.openclaw.gateway.plist && launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.openclaw.gateway.plist
  2. Open a Codex session and issue a prompt that forces the model into a long chain-of-thought between tool calls — e.g. "Read the following 8 files quickly, then think for two minutes about how they interact, then read 4 more."
  3. Observe: the first burst (pre-thinking) succeeds; the second burst (post-thinking) returns Native hook relay unavailable for every call until the turn ends.
  4. Cross-check openclaw hooks check immediately after — it will report all hooks Ready, confirming the diagnostic gap.
  5. Grep ~/.openclaw/agents/main/agent/codex-home/sessions/**/rollout-*.jsonl for "Native hook relay unavailable" to count occurrences across the day.

Rollout-file evidence is from the 2026.5.26 install at commit 10ad3aa; the reproduction status section above records retest results after upgrading to 2026.5.28 (e932160).

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.staleMarked as stale due to inactivity

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions