claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] Claude Code TS SDK expects the prompt stream to remain open while working

Open gsabran opened this issue 2 months ago • 4 comments

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

If the prompt is an AsyncIterable<SDKUserMessage> that is closed before Claude Code is done working, several features (hooks, canUseTool) are not called.

What Should Happen?

All features should work if the prompt's async iterable has completed before Claude Code is done.

Error Messages/Logs

Error in hook callback hook_0: Error: Stream closed

Steps to Reproduce

Claude Code TS SDK requires the following type for the prompt parameter: string | AsyncIterable<SDKUserMessage>

When sending messages other than a simple text, we have to use AsyncIterable<SDKUserMessage>. Several features, such as hooks, or canUseTool do not work when the AsyncIterable is not kept open while Claude Code is working (ref, ref). Other core features work. When adding a stderr handle, we see a log such as: Error in hook callback hook_0: Error: Stream closed

here's the query setup (unchanged between repros):

const queryHandle = query({
	prompt,
	options: {
		hooks: {
			PreToolUse: [
				{
					hooks: [
						async (input: HookInput): Promise<HookJSONOutput> => {
							console.log(`🔧 About to run tool: ${input.tool_name}`)
							return { continue: true }
						},
					],
				},
			],
		},
		stderr: (data: string) => {
			console.error(`Claude Code stderr: '${data}'`)
		},
	},
})

This works:

// Text message
const prompt = "Can you read the readme?"
const queryHandle = ...
for await (const event of queryHandle) {
	console.log(event)
}

This doesn't call the hook nor canUseTool, and stderr shows Error in hook callback hook_0: Error: Stream closed:

// Text message
const message: SDKUserMessage = { ... }
const prompt: AsyncIterable<SDKUserMessage> = {
	async *[Symbol.asyncIterator]() {
		yield message
	},
}
const queryHandle = ...
for await (const event of queryHandle) {
	console.log(event) // events are still logged, but the hook and canUseTool are not called as expected
}

keeping the prompt stream open fixes the issue:

let onReceiveResult: () => void = () => {}
const receivedResult = new Promise<void>((resolve) => {
	onReceiveResult = resolve
})


const message: SDKUserMessage = { ... }
const prompt: AsyncIterable<SDKUserMessage> = {
	async *[Symbol.asyncIterator]() {
		yield message
		await receivedResult
	},
}
const queryHandle = ...
for await (const event of queryHandle) {
	if (event.type == "result") {
		onReceiveResult()
	}
	console.log(event)
}

Claude Model

None

Is this a regression?

No, this never worked

Last Working Version

No response

Claude Code Version

claude: 2.0.20 / @anthropic-ai/[email protected]

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

In addition to fixing this bug, I would recommend the TS SDK to not require an async parameter, ie to accept string | SDKUserMessage[] | AsyncIterable<SDKUserMessage>

gsabran avatar Oct 17 '25 04:10 gsabran

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/7905
  2. https://github.com/anthropics/claude-code/issues/4775
  3. https://github.com/anthropics/claude-code/issues/6223

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

github-actions[bot] avatar Oct 17 '25 04:10 github-actions[bot]

I'm getting the same issue! I've tried to work around it by bumping how long the input stream stays open, but this doesn't seem like a sustainable solution long-term. Did you ever end up finding a solution?

henry-dowling avatar Nov 21 '25 08:11 henry-dowling

bumping it is the way to go for now

realPrimoh avatar Nov 21 '25 08:11 realPrimoh

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.

github-actions[bot] avatar Dec 21 '25 10:12 github-actions[bot]