Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate. ([Bug]: Command approvals stay pending after a delegated task is cancelled #21935 is related: approvals left pending after a delegated Codex task is cancelled. This one is a Claude run that keeps going after the CLI cancels the request.)
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- Add a
PermissionRequesthook to~/.claude/settings.jsonthat returns allow:
{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}} - Start a Claude thread in full-access mode (
bypassPermissions). - Have it run a command that trips Claude Code's bypass-immune check ("Dangerous rm operation not ruled out — the shell may read this command differently than it was parsed"). A harmless trigger:
typeset -A ids; ids=(a 1 b 2); for k in ${(k)ids}; do echo probe-$k; done - The hook allows the command and it runs right away. The thread still shows an "Approval needed" card, and the card stays until someone clicks it.
Expected behavior
When the CLI withdraws a can_use_tool request (control_cancel_request / SDK signal abort), the approval card clears, because the request no longer needs an answer.
Actual behavior
The card stays pending. Clicking Approve or Decline later does nothing, because the tool already ran.
In one real thread, the request opened at 21:32:18.938Z and the tool result arrived at 21:32:19.128Z. The row in orchestration_v2_projection_runtime_requests stayed pending until the user clicked at 21:51:23.624Z.
Likely cause, from reading the bundled server code: in the Claude adapter's canUseTool, awaitClaudeApprovalDecision resolves to cancel when signal aborts, and the ensuring cleanup removes the entry from pendingRuntimeRequests. But no runtime_request.updated / turn_item.updated event marks the request resolved or cancelled, so the projection and the UI keep it pending.
Context: the card appears in full-access threads at all because requiresClaudeApproval returns true whenever permissionMode === "bypassPermissions". With the CLI's bypass-immune safety checks, this means a hook-approved request still produces a card that can't be cleared.
Impact
Minor bug or occasional failure
Version or commit
0.1.4-nightly.20261028.3824
Environment
macOS (Darwin 27.0.0), desktop app (Nightly), Claude Code 2.1.312, claude-opus-5-5
Logs or stack traces
# Headless repro of the CLI side: claude -p over stream-json with --permission-prompt-tool stdio,
# --permission-mode bypassPermissions, and the PermissionRequest hook above. Host-side timeline:
[5.11s] control_request can_use_tool (Bash), decision_reason_type=safetyCheck
[5.18s] control_cancel_request for the same request_id
[6.39s] tool_result: "probe-a\nprobe-b"
# T3 projection row for the real thread (statev2.sqlite):
kind=command status=pending created_at=2026-10-29T21:32:18.938Z
# stayed pending until a manual click:
status=resolved resolved_at=2026-10-29T21:51:23.624ZWorkaround
Click either button. The click is a no-op, since the tool already ran.
Activity
juliusmarminge commentedon Oct 30, 2026
Closing as a duplicate of #24690, which tracks the same problem. Please follow along there.