[BUG][Typescript SDK] `canUseTool` callback in the Claude Code SDK is not working
Status Closed — not planned
Maintainer reply ✓ Yes — blois
Workaround ✓ Mentioned in thread ↓
Activity 11 comments · opened Jul 30, 2025 · closed Jan 10, 2026
💡 Likely answer: A maintainer (blois, collaborator)
responded on this thread — see the highlighted reply below.
Environment
- Platform (select one):
- [X] Anthropic API
- [ ] AWS Bedrock
- [ ] Google Vertex AI
- [ ] Other: <!-- specify -->
- Claude CLI version: 1.0.63 (Claude Code)
- Operating System: Ubuntu 24.04
- Terminal: via Typescript SDK
Bug Description
The canUseTool callback in the Claude Code SDK hangs indefinitely. The callback is invoked correctly and returns the proper response format, but Claude Code never proceeds.
Steps to Reproduce
- Use the SDK with
canUseToolcallback:
const { query } = require('@anthropic-ai/claude-code');
const stream = query({
prompt: (async function* () {
yield { type: 'user', message: { role: 'user', content: 'What is 2+2?' } };
})(),
options: {
canUseTool: (toolName, toolInput) => {
return { behavior: "allow", updatedInput: toolInput };
}
}
});
for await (const message of stream) {
if (message.type === 'result') break;
}
- Run the script
- Observe that the callback is called but the script hangs indefinitely
Expected Behavior
Tool execution should proceed after canUseTool returns { behavior: "allow", updatedInput: toolInput }
Actual Behavior
The process hangs indefinitely after the callback is invoked. Claude Code never proceeds.
Potential Fix
I found a potential fix that seem to work for me after patching my local node_modules. Modify streamToStdin to keep the stdin stream open when canUseTool is used:
In node_modules/@anthropic-ai/claude-code/sdk.mjs:
- Change line ~374:
// FROM:
async function streamToStdin(stream, stdin, abortController) {
// ... existing code ...
stdin.end();
}
// TO:
async function streamToStdin(stream, stdin, abortController, keepOpen = false) {
// ... existing code ...
if (!keepOpen) {
stdin.end();
}
}
- Change line ~198:
// FROM:
streamToStdin(prompt, child.stdin, abortController);
// TO:
streamToStdin(prompt, child.stdin, abortController, !!canUseTool);
11 Comments
Looking at a fix, the issue is that the input stream used to communicate the tool permission response is being closed when the prompt is being closed.
Workaround:
Thanks @blois! I can confirm that the workaround works (and is better than my very specific patch :-)).
Another fix will be arriving soon where Claude Code will not hang when this occurs and instead will reject the tool call (not desirable, but we need this to be reliable across all SDK surfaces).
@blois Any updates on this?
How does this work out? I do a couple of tasks that ask the user for permission and return true using this method. Will I have to refactor it to use the MCP option (which isn't ideal imho)
@blois
Any updates on this?
Any updates on this?
This issue of requiring the input stream to remain open also impacted hooks for me. I made another report with repro steps.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
This issue has been automatically closed due to 60 days of inactivity. If you're still experiencing this issue, please open a new issue with updated information.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.