AskUserQuestion auto-resolves with empty answers in Agent SDK programmatic mode (canUseTool never awaited)

Resolved 💬 2 comments Opened Mar 5, 2026 by aakashd Closed Apr 2, 2026

Description

When using the Claude Agent SDK (@anthropic-ai/claude-agent-sdk v0.2.63) programmatically with query(), the AskUserQuestion tool auto-resolves with empty answers even though a canUseTool callback is provided that should block until the user responds.

The canUseTool callback correctly awaits a Promise for user input, but the SDK appears to resolve AskUserQuestion internally before canUseTool completes, producing:

User has answered your questions: . You can now continue with the user's answers in mind.

SDK-Specific Context (Not CLI)

This is distinct from the CLI-based reports in #29530, #30207, #30679. We're using the Agent SDK to build a desktop app (Electron + Hono server) where:

  1. query() is called with canUseTool callback
  2. canUseTool detects AskUserQuestion, creates a pending Promise, emits an SSE event to our frontend
  3. The frontend should render a question UI, user selects answers, frontend POSTs response back
  4. The POST resolves the Promise, canUseTool returns {behavior: "allow", updatedInput: {answers: ...}}

What actually happens: The SDK resolves the tool instantly (same-second DB timestamp for tool_use and tool_result) without waiting for canUseTool to return.

Reproduction

import { query } from "@anthropic-ai/claude-agent-sdk";

const res = query({
  prompt: channel.generator(firstMessage),
  options: {
    permissionMode: "default", // NOT bypassPermissions
    canUseTool: async (toolName, input, options) => {
      if (toolName === "AskUserQuestion") {
        // This Promise should block until user responds via UI
        const response = await waitForUserResponse(options.toolUseID);
        return {
          behavior: "allow",
          updatedInput: { ...input, answers: response.answers },
        };
      }
      // ... other tools
    },
  },
});

for await (const message of res) {
  // tool_use and tool_result for AskUserQuestion arrive in the same iteration
  // with 0 seconds between them — canUseTool was never awaited
}

Evidence from DB Timestamps

We persisted all SDK messages to SQLite. For three separate AskUserQuestion calls in the same conversation:

| Tool Call ID | tool_use timestamp | tool_result timestamp | Gap |
|---|---|---|---|
| toolu_011pB2xD35TxBkSBbzpvxygU | 07:51:57 | 07:51:57 | 0s |
| toolu_0123mappWTVAJsbmjRGcEpps | 07:54:03 | 07:54:03 | 0s |
| toolu_01Sk2owtJbZfEDQ3BTS1Yopu | 07:55:46 | 07:55:46 | 0s |

All three resolved with empty answers: "User has answered your questions: ." — the user never saw any question UI.

SDK Source Analysis

In the minified cli.js (v0.2.63), the AskUserQuestion tool has:

  • requiresUserInteraction(){return!0} — should force canUseTool to be called
  • checkPermissions returns {behavior:"ask"} — should trigger the canUseTool flow
  • call({questions, answers={}})defaults answers to {} if not provided

The permission dispatch logic does route to canUseTool for tools with requiresUserInteraction: true. However, something in the execution pipeline resolves the tool before canUseTool's async return value is awaited.

Impact

Critical for SDK users building custom UIs. The canUseTool callback is the documented mechanism for intercepting AskUserQuestion in programmatic mode, but it's effectively a no-op — the tool resolves before the callback completes.

Environment

  • SDK: @anthropic-ai/claude-agent-sdk v0.2.63
  • Platform: macOS (Darwin 25.3.0, Apple M4 Pro)
  • Node: v22
  • Permission mode: default (not bypassPermissions)
  • App: Electron desktop app using SDK's query() with long-lived sessions via MessageChannel generator pattern

Related Issues

  • #29530 — Same symptoms in CLI mode (open, 23 upvotes)
  • #10400 — Fixed for bypassPermissions but not default mode
  • #30207, #30679, #30563, #30523 — Various related reports

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗