Skip to content

fix(telegram): bypass sequentializer for approval callback_queries#64979

Merged
obviyus merged 3 commits intoopenclaw:mainfrom
nk3750:fix/approval-sequentializer-deadlock
Apr 12, 2026
Merged

fix(telegram): bypass sequentializer for approval callback_queries#64979
obviyus merged 3 commits intoopenclaw:mainfrom
nk3750:fix/approval-sequentializer-deadlock

Conversation

@nk3750
Copy link
Copy Markdown
Contributor

@nk3750 nk3750 commented Apr 11, 2026

Summary

Fixes #64977 — plugin approval buttons on Telegram deadlock because the Grammy sequentializer queues the approval callback_query behind the blocked agent turn.

One file changed, one pattern followed. Same fix as abort requests (telegram:<chatId>:control) and btw requests (telegram:<chatId>:btw).

Root Cause

getTelegramSequentialKey() returns the same key (telegram:<chatId>) for both:

  • The user message that starts the agent turn (which blocks on plugin.approval.waitDecision)
  • The approval callback_query from clicking the inline button

The @grammyjs/runner sequentializer processes same-key updates sequentially. Deadlock: the callback can't run because the lane is held, and the lane can't release because it's waiting for the callback.

Fix

Detect approval callback_query updates via parseExecApprovalCommandText(data) and return a separate sequential key: telegram:<chatId>:approval.

This is the same pattern already used for:

  • Abort requests → telegram:<chatId>:control (line 40-44)
  • Btw requests → telegram:<chatId>:btw (line 46-54)

Before / After (gateway logs, same machine, same guardrail)

Before — approval times out after 300s, resolve arrives too late:

plugin.approval.waitDecision 299961ms  ✓  (timed out)
plugin.approval.resolve 0ms  ✗  errorCode=INVALID_REQUEST errorMessage=unknown or expired approval id
plugin.approval.resolve 1ms  ✗  errorCode=INVALID_REQUEST errorMessage=unknown or expired approval id

After — approval resolves in 3s:

plugin.approval.waitDecision 3147ms  ✓  (resolved by button click)
plugin.approval.resolve 564ms  ✓

Audit log confirms: decision: "approval_required" at 19:22:32, resolution: "allow-once", userResponse: "approved" at 19:22:35.

Changes

File Change
extensions/telegram/src/sequential-key.ts Add data?: string to callback_query context type. Detect approval callbacks via parseExecApprovalCommandText and return telegram:<chatId>:approval key.
extensions/telegram/src/sequential-key.test.ts 4 new tests: plugin approval, exec approval, allow-always variant, non-approval callback (no false positives). All 23 tests pass.

Test plan

  • pnpm test -- extensions/telegram/src/sequential-key.test.ts — 23/23 pass (19 existing + 4 new)
  • Plugin approval callback → telegram:<chatId>:approval key
  • Exec approval callback → telegram:<chatId>:approval key
  • always alias callback → telegram:<chatId>:approval key
  • Non-approval callback → normal telegram:<chatId> key (no false positives)
  • Live e2e: ClawLens guardrail require_approval → Telegram button click → resolves in 3s (was 300s timeout)

Environment

  • OpenClaw: 2026.4.10 (44e5b62) base, tested on 2026.4.11-beta.1 (faf9fe7)
  • Plugin: ClawLens (returns requireApproval from before_tool_call guardrails)
  • Channel: Telegram DM

🤖 Generated with Claude Code

@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: S labels Apr 11, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 11, 2026

Greptile Summary

This PR fixes a sequentializer deadlock on Telegram where approval callback_query updates shared the same lane key (telegram:<chatId>) as the blocked agent turn waiting on plugin.approval.waitDecision. The fix follows the established pattern used for abort (telegram:<chatId>:control) and btw (telegram:<chatId>:btw) requests, adding a dedicated telegram:<chatId>:approval lane by detecting approval callbacks via parseExecApprovalCommandText. The change is minimal, well-commented, and tested with 4 new cases (plugin approval, exec approval, always alias, and non-approval no-false-positive).

Confidence Score: 5/5

Safe to merge — targeted single-file fix that correctly resolves a real deadlock following the established lane-separation pattern.

No P0/P1 findings. The fix is minimal, correct, follows existing patterns for abort and btw lanes, uses a properly exported SDK function, and is covered by 4 new targeted tests.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(telegram): bypass sequentializer for..." | Re-trigger Greptile

@obviyus obviyus self-assigned this Apr 12, 2026
nk3750 and others added 2 commits April 12, 2026 09:55
Approval callback_queries from clicking inline buttons get the same
sequential key as the blocked agent turn (telegram:<chatId>), causing a
deadlock: the callback can't run because the lane is held, and the lane
can't release because it's waiting for the callback.

Give approval callbacks a separate lane (telegram:<chatId>:approval),
same pattern as abort requests (telegram:<chatId>:control) and btw
requests (telegram:<chatId>:btw).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@obviyus obviyus force-pushed the fix/approval-sequentializer-deadlock branch from c074e85 to 76165ab Compare April 12, 2026 04:25
Copy link
Copy Markdown
Contributor

@obviyus obviyus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the Telegram approval deadlock path: approval button callback queries were sharing the blocked chat lane, and the PR fixes that by routing /approve ... callbacks onto a separate sequentializer key.

Maintainer follow-up: trimmed the added explanatory comments, rebased onto latest main, and added the unreleased changelog entry for this user-facing fix.

Local gate: pnpm test extensions/telegram/src/sequential-key.test.ts.

@obviyus obviyus merged commit 22b53a4 into openclaw:main Apr 12, 2026
8 checks passed
@obviyus
Copy link
Copy Markdown
Contributor

obviyus commented Apr 12, 2026

Landed on main.

Thanks @nk3750.

trudbot pushed a commit to trudbot/openclaw that referenced this pull request Apr 12, 2026
…anks @nk3750)

* fix(telegram): bypass sequentializer for approval callback_queries

Approval callback_queries from clicking inline buttons get the same
sequential key as the blocked agent turn (telegram:<chatId>), causing a
deadlock: the callback can't run because the lane is held, and the lane
can't release because it's waiting for the callback.

Give approval callbacks a separate lane (telegram:<chatId>:approval),
same pattern as abort requests (telegram:<chatId>:control) and btw
requests (telegram:<chatId>:btw).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(telegram): trim approval lane comments

* fix: unblock Telegram approval callback deadlock (openclaw#64979) (thanks @nk3750)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
TOMUIV pushed a commit to TOMUIV/openclaw that referenced this pull request Apr 14, 2026
…anks @nk3750)

* fix(telegram): bypass sequentializer for approval callback_queries

Approval callback_queries from clicking inline buttons get the same
sequential key as the blocked agent turn (telegram:<chatId>), causing a
deadlock: the callback can't run because the lane is held, and the lane
can't release because it's waiting for the callback.

Give approval callbacks a separate lane (telegram:<chatId>:approval),
same pattern as abort requests (telegram:<chatId>:control) and btw
requests (telegram:<chatId>:btw).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(telegram): trim approval lane comments

* fix: unblock Telegram approval callback deadlock (openclaw#64979) (thanks @nk3750)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Telegram: plugin approval callback_query deadlocked by Grammy sequentializer

2 participants