openclaw - 💡(How to fix) Fix [Bug]: WhatsApp text /approve cannot resolve exec approvals, while Telegram resolves the same ID

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.18, WhatsApp can trigger an exec approval and receive the approval prompt, but a manually typed WhatsApp /approve <id> allow-once fails with:

Failed to submit approval: unknown or expired approval id

The same pending approval ID can then be approved successfully from Telegram, and the original command resumes and completes. This suggests the approval object is still valid and globally pending, but the WhatsApp text-command approval path cannot see or resolve it.

Error Message

  1. WhatsApp still fails with the same unknown or expired approval id error.
  • WhatsApp sender authorization does not show an auth error.

Root Cause

The approval ID is shown elsewhere in the prompt, but the Reply with: line omits it. This looks like a separate rendering bug and may confuse manual approval, but it does not explain this repro because both short ID and full UUID were manually typed and still failed.

Fix Action

Fix / Workaround

WhatsApp can be used to trigger commands and receive approval prompts, but manual WhatsApp approval is not reliable. Operators must use Telegram as a workaround for approval resolution.

Code Example

Failed to submit approval: unknown or expired approval id

---

Run: python3 /home/node/.openclaw/workspace/projects/health-fitness/scripts/health_raw_cleanup.py

Reply: DONE when the script completes.

---

/approve d8f84298 allow-once

---

Failed to submit approval: unknown or expired approval id

---

/approve d8f84298-34a5-4c29-b3e5-458157c103ec allow-once

---

[whatsapp] Inbound message ... (run request)
[ws] res ✓ exec.approval.request
[whatsapp] Sending message ...
[whatsapp] Sending message ...              # duplicate approval prompt
[telegram] outbound send ok ...             # approval also delivered to Telegram

[whatsapp] Inbound message ... (/approve ...)
[ws] res ✗ exec.approval.resolve errorCode=INVALID_REQUEST errorMessage=unknown or expired approval id
[ws] res ✗ plugin.approval.resolve errorCode=INVALID_REQUEST errorMessage=unknown or expired approval id

[ws] res ✓ exec.approval.waitDecision ...
[telegram] outbound send ok ...
[ws] res ✓ exec.approval.resolve ...         # Telegram resolves same approval successfully
[agent/embedded] strict-agentic execution contract active: runId=exec-approval-followup:<same-approval-id>:...
DONE

---

Reply with: /approve  allow-once|allow-always|deny
RAW_BUFFERClick to expand / collapse

Bug type

Approval routing / channel command handling bug

Summary

In OpenClaw 2026.5.18, WhatsApp can trigger an exec approval and receive the approval prompt, but a manually typed WhatsApp /approve <id> allow-once fails with:

Failed to submit approval: unknown or expired approval id

The same pending approval ID can then be approved successfully from Telegram, and the original command resumes and completes. This suggests the approval object is still valid and globally pending, but the WhatsApp text-command approval path cannot see or resolve it.

Environment

  • OpenClaw: 2026.5.18
  • Runtime: Docker gateway container on Windows 11 / WSL2 host
  • Agent: main
  • Channels involved: WhatsApp direct chat and Telegram
  • Approval config: approvals.exec.mode = "both"
  • Codex plugin disabled

Reproduction

  1. From WhatsApp direct chat, send an agent command that requires exec approval, for example:
Run: python3 /home/node/.openclaw/workspace/projects/health-fitness/scripts/health_raw_cleanup.py

Reply: DONE when the script completes.
  1. WhatsApp receives an exec approval prompt. In this repro, WhatsApp delivered the same prompt twice.

  2. Approve from WhatsApp using the short approval slug:

/approve d8f84298 allow-once
  1. WhatsApp replies:
Failed to submit approval: unknown or expired approval id
  1. Repeat with the full UUID:
/approve d8f84298-34a5-4c29-b3e5-458157c103ec allow-once
  1. WhatsApp still fails with the same unknown or expired approval id error.

  2. Approve the same pending ID from Telegram.

  3. Telegram succeeds, and the exec command resumes and completes.

Expected behavior

A WhatsApp /approve <id> allow-once command from an authorized operator should resolve a pending exec approval created by a WhatsApp-originated turn, just as Telegram approval does.

Actual behavior

WhatsApp receives the approval prompt but cannot resolve the pending approval ID. Telegram can resolve the same ID afterward, proving the ID was not expired or consumed.

Sanitized log evidence

Relevant sequence from gateway logs, sanitized:

[whatsapp] Inbound message ... (run request)
[ws] res ✓ exec.approval.request
[whatsapp] Sending message ...
[whatsapp] Sending message ...              # duplicate approval prompt
[telegram] outbound send ok ...             # approval also delivered to Telegram

[whatsapp] Inbound message ... (/approve ...)
[ws] res ✗ exec.approval.resolve errorCode=INVALID_REQUEST errorMessage=unknown or expired approval id
[ws] res ✗ plugin.approval.resolve errorCode=INVALID_REQUEST errorMessage=unknown or expired approval id

[ws] res ✓ exec.approval.waitDecision ...
[telegram] outbound send ok ...
[ws] res ✓ exec.approval.resolve ...         # Telegram resolves same approval successfully
[agent/embedded] strict-agentic execution contract active: runId=exec-approval-followup:<same-approval-id>:...
DONE

No unauthorized or Ignoring /approve from unauthorized sender message was observed in this repro.

Additional observations

The forwarded WhatsApp approval prompt renders a broken generic instruction line:

Reply with: /approve  allow-once|allow-always|deny

The approval ID is shown elsewhere in the prompt, but the Reply with: line omits it. This looks like a separate rendering bug and may confuse manual approval, but it does not explain this repro because both short ID and full UUID were manually typed and still failed.

The duplicate WhatsApp prompt is also likely a separate delivery/dedup issue with mode = "both", where the originating WhatsApp session route and an explicit WhatsApp target are both delivered because their route tuples are not byte-identical.

Source-inspection hypothesis

Inspection of the source suggests the failure may be a visibility/client-path mismatch rather than parsing or authorization.

The generic text /approve path appears to be:

  • src/auto-reply/reply/commands-approve.ts
  • parseApproveCommand(...) parses /approve d8f84298 allow-once
  • handleApproveCommand(...) calls exec.approval.resolve through plain callGateway
  • the ID passed is parsed.id

By contrast, Telegram inline approval appears to use an operator approval-runtime client path:

  • extensions/telegram/src/exec-approval-resolver.ts
  • resolveApprovalOverGateway(...)
  • uses approvalRuntimeToken / approval-runtime client visibility

Gateway approval visibility appears to check admin/operator approval-runtime visibility first, then falls back to record-specific device/connection/client identity. A generic WhatsApp text-command callGateway connection may pass sender authorization but still be unable to see a pending approval bound to another device/connection/client identity, causing the resolver to return unknown or expired approval id.

This would explain why:

  • WhatsApp sender authorization does not show an auth error.
  • WhatsApp resolver returns unknown or expired approval id.
  • Telegram can resolve the same approval afterward.

Suggested fix direction

After the existing sender authorization checks pass in handleApproveCommand, generic text /approve resolution may need to use the same approval-runtime resolver path as Telegram inline approval, for example resolveApprovalOverGateway(...), instead of plain callGateway.

The important security constraint is that the approval-runtime resolver should only be used after the existing human/channel authorization checks have passed. The proposed change should be a transport/visibility fix, not an auth bypass.

Impact

WhatsApp can be used to trigger commands and receive approval prompts, but manual WhatsApp approval is not reliable. Operators must use Telegram as a workaround for approval resolution.

Not included

No phone numbers, chat IDs, group IDs, raw session JSONL, tokens, hostnames, or private runtime logs are included in this report.

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

A WhatsApp /approve <id> allow-once command from an authorized operator should resolve a pending exec approval created by a WhatsApp-originated turn, just as Telegram approval does.

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]: WhatsApp text /approve cannot resolve exec approvals, while Telegram resolves the same ID