openclaw - ✅(Solved) Fix [Bug]: Elevated exec fails after approval callback in 2026.4.26 [2 pull requests, 1 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#74646Fetched 2026-04-30 06:21:41
View on GitHub
Comments
0
Participants
1
Timeline
9
Reactions
0
Participants
Timeline (top)
referenced ×4cross-referenced ×2labeled ×2closed ×1

Elevated exec commands that require interactive approval (via Telegram inline buttons) fail on the followup run after the user approves. The sendExecApprovalFollowup spawned run does not inherit the provider context from the originating Telegram session, causing the elevated permission check to fail with provider=null.

This makes elevated exec unusable in any flow that requires approval — which is the default for most elevated commands.

Error Message

The agent receives no output. The session resume also fails, and the raw error + internal context is dumped to the Telegram chat with an "Automatic session resume failed" prefix. → Raw error dumped to Telegram

  1. Session resume leak: When the followup run fails, the error recovery path dumps raw internal context to the Telegram chat, including tool call metadata and error traces.

Root Cause

Three related code paths contribute to elevated exec flapping. Root cause #3 is the one introduced/worsened in 2026.4.26:

Fix Action

Fix / Workaround

Workarounds Attempted

WorkaroundResult
allowFrom.telegram: ["*"]Doesn't help — provider is null in
followup, never reaches telegram key
allowFrom.telegram: ["8676994316"]Same — null provider
Local source patch of get-reply-*.js to hardcode `elevatedEnabled:
true`Fixes direct runs but not approval followup runs (separate
code path)
Patching compact.ts and agent-runner-memory.tsFixes root
causes 1 and 2 but not 3

No config-level workaround exists for root cause #3.

PR fix notes

PR #74666: fix(exec): preserve turnSourceChannel as messageProvider in approval followup runs

Description (problem / solution / changelog)

When an exec-approval followup run has no deliverable route and no gateway-internal channel, buildAgentFollowupArgs was passing channel=undefined to the spawned agent. This left defaults.messageProvider=undefined in the followup run, causing tools.elevated.allowFrom.<provider> checks to always fail with provider=null after the user approves an async elevated command.

Root cause: buildAgentFollowupArgs only set channel to sessionOnlyOriginChannel when deliveryTarget.deliver=false. But sessionOnlyOriginChannel is only set when turnSourceChannel is a gateway message channel — plain channel names like "telegram" fail isGatewayMessageChannel and produce undefined, dropping the channel context from the followup run.

Fix: Thread turnSourceChannel through buildAgentFollowupArgs and use it as a fallback (sessionOnlyOriginChannel ?? turnSourceChannel) so the raw channel name is always propagated as messageProvider on the followup run.

Test: Added regression test "preserves turnSourceChannel as messageProvider on the followup run when no deliverable route exists" — verifies channel: "telegram" is set on the callGatewayTool call even when no deliverable route exists. 32/32 tests pass.

Fixes #74646. Thanks @xhd2015.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/bash-tools.exec-approval-followup.test.ts (modified, +22/-0)
  • src/agents/bash-tools.exec-approval-followup.ts (modified, +7/-1)

PR #14: fix(exec): compute bashElevated in gateway agent path to fix followup elevated exec errors

Description (problem / solution / changelog)

Fixes #74646.

Root cause

runAgentAttempt in src/commands/agent.ts never assembled a bashElevated (ExecElevatedDefaults) value before calling runEmbeddedPiAgent. When an agent turn is spawned via sendExecApprovalFollowupcallGatewayTool("agent", ...), the followup run has no elevated context, so defaults?.elevated is undefined inside bash-tools.exec.ts.

The "enabled" gate check then fails unconditionally:

elevated is not available right now (runtime=sandboxed).
Failing gates: enabled (tools.elevated.enabled / agents.list[].tools.elevated.enabled)

This happens even when the user has elevated exec properly configured, because the value was simply never computed and passed in.

Fix

runAgentAttempt now computes bashElevated from the effective config before each runEmbeddedPiAgent call:

  • enabled reflects global tools.elevated.enabled AND per-agent agents.list[].tools.elevated.enabled (both must be non-false).
  • allowed is true only when enabled is true AND senderIsOwner is true (admin-scope callers, i.e. CLI operators). Gateway tool calls use WRITE_SCOPE, so senderIsOwner=false there — elevated stays blocked with the correct "allowFrom" gate error instead of the misleading "enabled" gate.
  • defaultLevel defaults to "ask" matching the channel-originated path.

Channel-originated paths (Telegram, Discord, etc.) already compute bashElevated via get-reply-directives.ts with full sender identity and are unaffected.

Regression test

Five new cases in src/commands/agent.test.ts under describe("bashElevated defaults"):

  1. senderIsOwner=true + elevated not configured → enabled=true, allowed=true
  2. senderIsOwner=false → enabled=true, allowed=false
  3. senderIsOwner=true + tools.elevated.enabled=false → enabled=false, allowed=false
  4. senderIsOwner=true + tools.elevated.enabled=true → enabled=true, allowed=true
  5. senderIsOwner=false + tools.elevated.enabled=true → enabled=true, allowed=false

All five previously would have received bashElevated=undefined; now they receive a properly shaped object, and the "enabled" gate no longer fires spuriously.

Testing

pnpm tsgo   # zero errors
pnpm test   # 37 pass (1 pre-existing failure unrelated to this change)

Generated by Claude Code

<!-- devin-review-badge-begin -->
<a href="https://app.devin.ai/review/suboss87/openclaw/pull/14" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review"> </picture> </a> <!-- devin-review-badge-end -->

Changed files

  • src/commands/agent.test.ts (modified, +67/-0)
  • src/commands/agent.ts (modified, +18/-0)
  • src/cron/service.cron-invalid-expr.test.ts (added, +133/-0)
  • src/cron/service/ops.ts (modified, +9/-0)
  • src/cron/validate-timestamp.ts (modified, +23/-0)
  • src/gateway/server-methods/cron.ts (modified, +18/-1)

Code Example

{
"tools": {
"elevated": {
"enabled": true,
"allowFrom": {
"telegram": ["*"]
}
}
}
}

---

User: "check the system logs"
Agent calls exec with elevated: true

---

elevated is not available right now (runtime=sandboxed).
Failing gates: enabled (tools.elevated.enabled / agents.list[].tools.elevated.enabled)
Context: provider=telegram session=agent:main:telegram:direct:<chat_id>

---

## Root Cause Analysis

Three related code paths contribute to elevated exec flapping. Root
cause #3 is the one introduced/worsened in 2026.4.26:

### Root Cause 1`compact.ts` hardcodes elevated off
- After context compaction, `compact.ts` hardcodes `bashElevated:
{enabled: false, allowed: false}`
- Any elevated exec attempted after compaction will fail
- **Related issue:** #18834

### Root Cause 2`agent-runner-memory.ts` hardcodes elevated off for
heartbeat/fast-directive
- Heartbeat and fast-directive runs set `elevatedAllowed: false`
- Elevated exec during heartbeat-triggered work fails
- **Related issue:** #30379

### Root Cause 3Approval followup runs don't inherit provider
context (PRIMARY BUG)
- When `sendExecApprovalFollowup` spawns a new agent run to deliver
the approved command's output, the spawned run has `provider = null`
- The 2026.4.26 elevated permission check now hard-requires a known
provider before evaluating `allowFrom`
- With `provider = null`, no `allowFrom` entry can match —
`allowFrom.telegram: ["*"]` doesn't help because the check never
reaches the telegram key
- **Related issue:** #40034

### Deterministic pattern:
- `provider=telegram` (direct user message triggers exec)**elevated works**- `exec-approval-followup` (spawned after user taps approve button)**elevated fails**- The flapping appears random but is actually deterministic based on
which code path triggered the run
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

Elevated exec commands that require interactive approval (via Telegram inline buttons) fail on the followup run after the user approves. The sendExecApprovalFollowup spawned run does not inherit the provider context from the originating Telegram session, causing the elevated permission check to fail with provider=null.

This makes elevated exec unusable in any flow that requires approval — which is the default for most elevated commands.

Steps to reproduce

  1. Configure elevated exec for Telegram:
{
"tools": {
"elevated": {
"enabled": true,
"allowFrom": {
"telegram": ["*"]
}
}
}
}
  1. From a Telegram direct chat, trigger any elevated exec:
User: "check the system logs"
Agent calls exec with elevated: true
  1. OpenClaw sends an approval card to Telegram with inline buttons (Allow Once / Allow Always / Deny).

  2. User taps "Allow Once."

Expected behavior

The command executes with elevated privileges and returns output to the agent.

Actual behavior

The approval followup run fails with:

elevated is not available right now (runtime=sandboxed).
Failing gates: enabled (tools.elevated.enabled / agents.list[].tools.elevated.enabled)
Context: provider=telegram session=agent:main:telegram:direct:<chat_id>

The agent receives no output. The session resume also fails, and the raw error + internal context is dumped to the Telegram chat with an "Automatic session resume failed" prefix.

OpenClaw version

OpenClaw 2026.4.26 (be8c246)

Operating system

Ubuntu 24.04, Docker sandbox, Telegram channel

Install method

npm global

Model

Anthropic Opus 4-6

Provider / routing chain

/usr/bin/openclaw -> ../lib/node_modules/openclaw/openclaw.mjs

Additional provider/model setup details

User taps "Allow Once" on Telegram inline button → Telegram callback_query arrives at Gateway → Gateway calls sendExecApprovalFollowup → Followup spawns a new agent run (provider=null ← BUG) → Elevated check: allowFrom[???] — no provider to match → Fails with "elevated is not available" → Session resume fails → Raw error dumped to Telegram

Logs, screenshots, and evidence

## Root Cause Analysis

Three related code paths contribute to elevated exec flapping. Root
cause #3 is the one introduced/worsened in 2026.4.26:

### Root Cause 1 — `compact.ts` hardcodes elevated off
- After context compaction, `compact.ts` hardcodes `bashElevated:
{enabled: false, allowed: false}`
- Any elevated exec attempted after compaction will fail
- **Related issue:** #18834

### Root Cause 2 — `agent-runner-memory.ts` hardcodes elevated off for
heartbeat/fast-directive
- Heartbeat and fast-directive runs set `elevatedAllowed: false`
- Elevated exec during heartbeat-triggered work fails
- **Related issue:** #30379

### Root Cause 3 — Approval followup runs don't inherit provider
context (PRIMARY BUG)
- When `sendExecApprovalFollowup` spawns a new agent run to deliver
the approved command's output, the spawned run has `provider = null`
- The 2026.4.26 elevated permission check now hard-requires a known
provider before evaluating `allowFrom`
- With `provider = null`, no `allowFrom` entry can match —
`allowFrom.telegram: ["*"]` doesn't help because the check never
reaches the telegram key
- **Related issue:** #40034

### Deterministic pattern:
- `provider=telegram` (direct user message triggers exec) → **elevated works** ✅
- `exec-approval-followup` (spawned after user taps approve button)**elevated fails** ❌
- The flapping appears random but is actually deterministic based on
which code path triggered the run

Impact and severity

  1. Session resume leak: When the followup run fails, the error recovery path dumps raw internal context to the Telegram chat, including tool call metadata and error traces.

  2. Sandbox state loss: The sandbox container appears to get recycled during the failed followup, causing mounted files (e.g.,.hook-auth) to intermittently disappear. Subsequent exec calls in the same session fail with FileNotFoundError until the container stabilizes.

  3. Inconsistent elevated availability: Within a single conversation, some elevated calls work (user-initiated) and some don't (approval-followup), making the feature appear unreliable.

Additional information

Workarounds Attempted

WorkaroundResult
allowFrom.telegram: ["*"]Doesn't help — provider is null in
followup, never reaches telegram key
allowFrom.telegram: ["8676994316"]Same — null provider
Local source patch of get-reply-*.js to hardcode `elevatedEnabled:
true`Fixes direct runs but not approval followup runs (separate
code path)
Patching compact.ts and agent-runner-memory.tsFixes root
causes 1 and 2 but not 3

No config-level workaround exists for root cause #3.


Suggested Fix

sendExecApprovalFollowup should propagate the originating session's provider context (and channel metadata) to the spawned followup run. The followup run should inherit:

  • provider (e.g., "telegram")
  • senderId (the user who approved)
  • channelId / chatId

This would allow the elevated permission check to correctly evaluate allowFrom in the followup path.


Environment Details

  • OS: Ubuntu 24.04 (6.8.0-110-generic, x64)
  • Node: v22.22.1
  • OpenClaw: 2026.4.26 (be8c246)
  • Sandbox: Docker-based, workspace mounted rw
  • Channel: Telegram (direct chat)
  • Agent: main (Claude Opus 4-6)
  • Elevated config: tools.elevated.enabled: true, allowFrom.telegram: ["*"]

Related Issues

  • #18834 — compact.ts hardcodes elevated off
  • #30379 — agent-runner-memory.ts heartbeat elevated
  • #40034 — approval callback provider context

extent analysis

TL;DR

The most likely fix is to modify the sendExecApprovalFollowup function to propagate the originating session's provider context to the spawned followup run.

Guidance

  • Identify the sendExecApprovalFollowup function and modify it to pass the provider context from the original session to the followup run.
  • Ensure the followup run inherits the senderId, channelId, and chatId from the original session.
  • Verify that the elevated permission check correctly evaluates allowFrom in the followup path after making these changes.
  • Review related issues (#18834, #30379, #40034) to ensure that all root causes are addressed.

Example

// Pseudo-code example of modifying sendExecApprovalFollowup
function sendExecApprovalFollowup(originalSession) {
  const followupRun = spawnNewRun();
  followupRun.provider = originalSession.provider; // Propagate provider context
  followupRun.senderId = originalSession.senderId;
  followupRun.channelId = originalSession.channelId;
  followupRun.chatId = originalSession.chatId;
  // ... rest of the function ...
}

Notes

The provided solution assumes that the sendExecApprovalFollowup function can be modified to propagate the necessary context. If this is not possible, alternative solutions may need to be explored.

Recommendation

Apply the workaround by modifying the sendExecApprovalFollowup function to propagate the provider context, as this directly addresses the primary bug causing 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…

FAQ

Expected behavior

The command executes with elevated privileges and returns output to the agent.

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]: Elevated exec fails after approval callback in 2026.4.26 [2 pull requests, 1 participants]