Skip to content

[Bug]: Claude approval card stays pending after the CLI cancels the permission request #27282

Closed as not planned

Description

@joshfcc

Before submitting

Area

apps/server

Steps to reproduce

  1. Add a PermissionRequest hook to ~/.claude/settings.json that returns allow:
    {"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}
  2. Start a Claude thread in full-access mode (bypassPermissions).
  3. 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
  4. 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.624Z

Workaround

Click either button. The click is a no-op, since the tool already ran.

Activity

  1. juliusmarminge commented on Oct 30, 2026

    @juliusmarminge
    Member

    Closing as a duplicate of #24690, which tracks the same problem. Please follow along there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions