openclaw - ✅(Solved) Fix [Bug]: before_tool_call plugin approval fails with 'no approval route' — turnSourceChannel not passed to plugin.approval.request [1 pull requests, 2 comments, 2 participants]

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…
GitHub stats
openclaw/openclaw#74003Fetched 2026-04-30 06:30:01
View on GitHub
Comments
2
Participants
2
Timeline
7
Reactions
0
Author
Timeline (top)
referenced ×3commented ×2cross-referenced ×2

Error Message

The gateway needs these fields to route the approval prompt to the correct channel and chat. Without them, plugin.approval.request returns decision: null, which triggers the "Plugin approval unavailable (no approval route)" error path.

Root Cause

In src/agents/pi-tools.before-tool-call.ts, the requestPluginToolApproval function calls plugin.approval.request with these fields:

callGatewayTool("plugin.approval.request", ..., {
    pluginId, title, description, severity,
    toolName, toolCallId, agentId, sessionKey,
    timeoutMs, twoPhase: true,
    // ❌ missing: turnSourceChannel, turnSourceTo, turnSourceAccountId
});

The agent runtime already injects turnSourceChannel (e.g. "telegram"), turnSourceTo (e.g. chat id), and turnSourceAccountId into the tool params (args.params) before invoking the tool. But requestPluginToolApproval does not forward them to plugin.approval.request.

The gateway needs these fields to route the approval prompt to the correct channel and chat. Without them, plugin.approval.request returns decision: null, which triggers the "Plugin approval unavailable (no approval route)" error path.

Compare with exec.approval.request which correctly receives route metadata.

Fix Action

Fixed

PR fix notes

PR #74150: fix(agents): forward turnSource* routing fields to plugin.approval.request (#74003)

Description (problem / solution / changelog)

Fixes #74003.

Problem

When a plugin tool has requireApproval: true (or returns requireApproval: true from onCall), the agent runtime calls plugin.approval.request to ask the user to approve. The gateway routes that prompt back to the originating channel using turnSource{Channel,To,AccountId,ThreadId} fields.

But requestPluginToolApproval in src/agents/pi-tools.before-tool-call.ts does not forward those routing fields when it builds the approval request. Result: plugin.approval.request returns decision: null because it has no channel to route to, and the user sees "Plugin approval unavailable (no approval route)" instead of the actual approval prompt.

Fix

Read turnSourceChannel, turnSourceTo, turnSourceAccountId, and turnSourceThreadId off params.baseParams (the agent runtime injects them there before the before-tool-call hook fires — see bash-tools.exec-host-shared.ts for the pattern), and forward them when calling plugin.approval.request.

Tests

  • New regression test in pi-tools.before-tool-call.test.ts asserts that the four turnSource* fields are passed through to the mock approval implementation when present.
  • New regression test asserts they are simply omitted (not set to undefined) when missing from baseParams, so existing approval routing logic stays unchanged.

Repro before fix

Set up any plugin tool with requireApproval: true, invoke it via Telegram/Discord/Slack — agent surfaces "Plugin approval unavailable (no approval route)" and tool returns decision: null.

After fix

Same flow now sees the approval prompt rendered in the originating channel and the user can approve/reject.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/pi-tools.before-tool-call.e2e.test.ts (modified, +68/-0)
  • src/agents/pi-tools.before-tool-call.ts (modified, +26/-0)

Code Example

Plugin approval unavailable (no approval route)

---

callGatewayTool("plugin.approval.request", ..., {
    pluginId, title, description, severity,
    toolName, toolCallId, agentId, sessionKey,
    timeoutMs, twoPhase: true,
    // ❌ missing: turnSourceChannel, turnSourceTo, turnSourceAccountId
});

---

twoPhase: true,
+ turnSourceChannel: args.params?.turnSourceChannel,
+ turnSourceTo: args.params?.turnSourceTo,
+ turnSourceAccountId: args.params?.turnSourceAccountId,
RAW_BUFFERClick to expand / collapse

Bug Description

When a before_tool_call hook returns requireApproval, the plugin approval flow fails with:

Plugin approval unavailable (no approval route)

The approval cannot be routed to the originating channel (e.g. Telegram) because the routing metadata is never passed to plugin.approval.request.

Root Cause

In src/agents/pi-tools.before-tool-call.ts, the requestPluginToolApproval function calls plugin.approval.request with these fields:

callGatewayTool("plugin.approval.request", ..., {
    pluginId, title, description, severity,
    toolName, toolCallId, agentId, sessionKey,
    timeoutMs, twoPhase: true,
    // ❌ missing: turnSourceChannel, turnSourceTo, turnSourceAccountId
});

The agent runtime already injects turnSourceChannel (e.g. "telegram"), turnSourceTo (e.g. chat id), and turnSourceAccountId into the tool params (args.params) before invoking the tool. But requestPluginToolApproval does not forward them to plugin.approval.request.

The gateway needs these fields to route the approval prompt to the correct channel and chat. Without them, plugin.approval.request returns decision: null, which triggers the "Plugin approval unavailable (no approval route)" error path.

Compare with exec.approval.request which correctly receives route metadata.

Steps to Reproduce

  1. Configure a plugin that returns requireApproval from before_tool_call hook
  2. Trigger a tool call via Telegram (or any chat channel)
  3. The approval request is generated but gateway cannot route it
  4. Agent sees: "Plugin approval unavailable (no approval route)"

The bug is consistent — it affects all channels because the routing metadata is never sent.

Proposed Fix

Pass the routing fields from args.params to plugin.approval.request:

  twoPhase: true,
+ turnSourceChannel: args.params?.turnSourceChannel,
+ turnSourceTo: args.params?.turnSourceTo,
+ turnSourceAccountId: args.params?.turnSourceAccountId,

These fields are already available — the agent runtime injects them into tool params before calling the tool. They just need to be forwarded.

Environment

  • OpenClaw: 2026.4.26 (npm global install)
  • Channel: Telegram
  • OS: Linux

Related

  • #57339 — Telegram plugin approval handler fix (handler side, not the routing side)
  • #64977 — Grammy sequentializer deadlock with plugin approvals
  • #54855 — Similar "missing channel" issue for Control UI exec approvals

extent analysis

TL;DR

Pass the routing fields from args.params to plugin.approval.request to fix the plugin approval flow.

Guidance

  • Verify that the turnSourceChannel, turnSourceTo, and turnSourceAccountId fields are present in args.params before passing them to plugin.approval.request.
  • Update the requestPluginToolApproval function in src/agents/pi-tools.before-tool-call.ts to include the missing routing metadata.
  • Test the approval flow with different channels (e.g., Telegram) to ensure the fix works as expected.
  • Review related issues (#57339, #64977, #54855) to ensure this fix does not introduce any regressions.

Example

callGatewayTool("plugin.approval.request", ..., {
    pluginId, title, description, severity,
    toolName, toolCallId, agentId, sessionKey,
    timeoutMs, twoPhase: true,
    turnSourceChannel: args.params?.turnSourceChannel,
    turnSourceTo: args.params?.turnSourceTo,
    turnSourceAccountId: args.params?.turnSourceAccountId,
});

Notes

This fix assumes that the turnSourceChannel, turnSourceTo, and turnSourceAccountId fields are correctly injected into args.params by the agent runtime.

Recommendation

Apply the proposed fix by passing the routing fields from args.params to plugin.approval.request, as it directly addresses the root cause of the issue.

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…

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 - ✅(Solved) Fix [Bug]: before_tool_call plugin approval fails with 'no approval route' — turnSourceChannel not passed to plugin.approval.request [1 pull requests, 2 comments, 2 participants]