openclaw - 💡(How to fix) Fix [Bug]: OpenClaw can persist `tool.call` without a matching `tool.result` when a Codex turn is denied, interrupted, or terminated

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

In OpenClaw 2026.5.24-beta.2, a native Codex tool invocation can be recorded as tool.call without a matching tool.result in the persisted transcript/trajectory. This has been observed when the Codex turn is denied, interrupted by a gateway restart, or finishes with a terminal assistant message before the tool result is emitted.

This appears to be a runtime invariant bug, not a configuration issue. The safety behavior should be: if a tool call was started but no real result is available, OpenClaw should synthesize a failed tool.result, mark the turn/job as failed, and preserve terminal proof for cron/reporting consumers.

Error Message

error: OpenClaw recorded a tool.call without a matching tool.result before the Codex turn completed warn cron {"module":"cron"} {"jobName":"agent-ops-approval-daily","error":"cron classifier: denial token "SYSTEM_RUN_DENIED" detected in final text","diagnosticsSummary":"cron classifier: denial token "SYSTEM_RUN_DENIED" detected in final text"} cron: job run returned error status status: error error: cron: job interrupted by gateway restart

Root Cause

If the real tool result cannot be emitted because the turn was denied, interrupted, or terminated, OpenClaw should fail closed by recording a synthetic failed tool.result, for example:

Fix Action

Fix / Workaround

Local diagnostic patch direction:

The patch approach was to update the Codex app-server event projector so terminal result construction checks for any recorded tool call without a matching tool result. Missing results are synthesized as failed tool.result records, and the turn is marked fail-closed with SYSTEM_RUN_DENIED / missing_tool_result proof.

RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

In OpenClaw 2026.5.24-beta.2, a native Codex tool invocation can be recorded as tool.call without a matching tool.result in the persisted transcript/trajectory. This has been observed when the Codex turn is denied, interrupted by a gateway restart, or finishes with a terminal assistant message before the tool result is emitted.

This appears to be a runtime invariant bug, not a configuration issue. The safety behavior should be: if a tool call was started but no real result is available, OpenClaw should synthesize a failed tool.result, mark the turn/job as failed, and preserve terminal proof for cron/reporting consumers.

Steps to reproduce

  1. Run an OpenClaw cron job or isolated agent turn that uses the Codex native runtime and invokes a local command/tool.
  2. Cause the turn to be denied or interrupted before the native tool result is emitted. Observed cases include:
    • a denied shell/tool command that results in final assistant text containing SYSTEM_RUN_DENIED
    • a gateway restart while the cron session has already emitted tool.call
  3. Inspect the persisted cron/session trajectory.
  4. Observe that tool.call exists, but no matching tool.result exists for the same tool call id.
  5. Observe that downstream cron/read-model/reporting logic has incomplete terminal proof and cannot reliably distinguish “runtime failed before producing proof” from “tool completed but report was lost”.

Expected behavior

Every persisted tool.call should have exactly one matching terminal tool.result before the turn result is finalized.

If the real tool result cannot be emitted because the turn was denied, interrupted, or terminated, OpenClaw should fail closed by recording a synthetic failed tool.result, for example:

status: failed
reason: missing_tool_result
error: OpenClaw recorded a tool.call without a matching tool.result before the Codex turn completed

The turn/job should then be classified as failed or unproven, and cron/reporting/dashboard consumers should have durable terminal proof instead of an incomplete trajectory.

Actual behavior

OpenClaw can persist a tool.call without a matching tool.result.

Observed outcomes:

  • cron detects SYSTEM_RUN_DENIED in final assistant text and marks the job as failed
  • another cron run is marked failed because it was interrupted by gateway restart
  • the persisted session trajectory contains tool.call but no matching tool.result
  • there is no model.completed / session.ended proof in at least one interrupted case
  • downstream reporting may have no user-visible failure report because no terminal runtime proof exists
  • dashboard/read-model layers can only classify the symptom after the fact; they cannot reconstruct the missing tool result invariant

OpenClaw version

2026.5.24-beta.2

Operating system

macOS 26.5

Install method

npm grobal

Model

openai/gpt-5.5

Provider / routing chain

openclaw -> codex -> openai/gpt-5.5

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

Severity: High for cron/workflow reliability.

Impact:

  • Cron jobs can fail without durable terminal tool proof.
  • User-visible failure reports can be lost because reporting has no completed runtime result to report from.
  • Read models and dashboards must infer from incomplete state instead of relying on a strict transcript invariant.
  • Automation can become ambiguous after gateway restarts or denied tool invocations.
  • Operators may be tempted to bypass cron with direct launchers, but the correct fix is to restore the invariant in the shared Codex/OpenClaw runtime layer.

This is especially risky for approval/publish/report workflows, where OpenClaw must distinguish successful publish, failed publish, interrupted runtime, and missing proof without guessing.

Additional information

Environment

  • OpenClaw version: 2026.5.24-beta.2
  • Runtime: OpenAI Codex native runtime via OpenClaw app-server
  • Affected area: cron / isolated agent turns / Codex native tool projection / persisted transcript and trajectory
  • Observed with scheduled approval/content automation jobs that invoke local runtime wrappers through the normal cron-owned path

Logs, screenshots, and evidence

Cron warning example:

warn cron {"module":"cron"} {"jobName":"agent-ops-approval-daily","error":"cron classifier: denial token \"SYSTEM_RUN_DENIED\" detected in final text","diagnosticsSummary":"cron classifier: denial token \"SYSTEM_RUN_DENIED\" detected in final text"}
cron: job run returned error status

Another observed cron run state:

jobName: agent-ops-approval-daily
status: error
error: cron: job interrupted by gateway restart
deliveryStatus: unknown

Trajectory evidence from the interrupted run:

session.started
tool.call emitted for the expected command
no matching tool.result
no model.completed
no session.ended

Observed denial final text shape:

SYSTEM_RUN_DENIED ... did not run the owned wrapper

Local diagnostic patch direction:

Fail closed on missing Codex tool results

The patch approach was to update the Codex app-server event projector so terminal result construction checks for any recorded tool call without a matching tool result. Missing results are synthesized as failed tool.result records, and the turn is marked fail-closed with SYSTEM_RUN_DENIED / missing_tool_result proof.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Every persisted tool.call should have exactly one matching terminal tool.result before the turn result is finalized.

If the real tool result cannot be emitted because the turn was denied, interrupted, or terminated, OpenClaw should fail closed by recording a synthetic failed tool.result, for example:

status: failed
reason: missing_tool_result
error: OpenClaw recorded a tool.call without a matching tool.result before the Codex turn completed

The turn/job should then be classified as failed or unproven, and cron/reporting/dashboard consumers should have durable terminal proof instead of an incomplete trajectory.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: OpenClaw can persist `tool.call` without a matching `tool.result` when a Codex turn is denied, interrupted, or terminated