[BUG] Claude Code repeatedly retries after a mid-tool provider disconnect
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 provider connection closes after a streamed tool call has been delivered but before a clean message completion, Claude Code repeatedly retries the same provider interaction instead of failing boundedly.
Severity / performance impact: High. A transient provider disconnect after tool-call delivery can create an unbounded retry loop and repeated local tool execution attempts.
Complete self-contained reproducer: https://gist.github.com/N0zoM1z0/885fa13bdb202b84b595050188174557
The Gist contains claude-post-tool-transient-disconnect.reproduce.py. Download and run:
gh gist clone 885fa13bdb202b84b595050188174557 claude-post-tool-transient-disconnect-reproducer
cd claude-post-tool-transient-disconnect-reproducer
python3 claude-post-tool-transient-disconnect.reproduce.py
To reuse an already-built local image:
python3 claude-post-tool-transient-disconnect.reproduce.py --skip-build
Complete self-contained reproducer: reports/claude-code/claude-post-tool-transient-disconnect.reproduce.py
Run from this repository checkout:
python3 reports/claude-code/claude-post-tool-transient-disconnect.reproduce.py
To reuse an already-built local image:
python3 reports/claude-code/claude-post-tool-transient-disconnect.reproduce.py --skip-build
Key output from a local run against the affected version:
provider_requests=1201
closed_mid_stream=1201
process_timed_out=True
REPRODUCED
The reproducer builds Claude Code from the public npm package and runs Docker with 2 CPUs and 4 GiB RAM by default.
What Should Happen?
Claude Code should cap retries and preserve enough turn state to avoid repeatedly treating the same partial streamed tool call as a fresh action.
Error Messages/Logs
closed_mid_stream=1201
process_timed_out=True
REPRODUCED
Steps to Reproduce
- Run the self-contained reproducer.
- The local mock provider streams a
Bashtool call and then closes the SSE connection mid-stream. - Observe repeated provider requests until the reproducer timeout.
Complete self-contained reproducer: https://gist.github.com/N0zoM1z0/885fa13bdb202b84b595050188174557
The Gist contains claude-post-tool-transient-disconnect.reproduce.py. Download and run:
gh gist clone 885fa13bdb202b84b595050188174557 claude-post-tool-transient-disconnect-reproducer
cd claude-post-tool-transient-disconnect-reproducer
python3 claude-post-tool-transient-disconnect.reproduce.py
To reuse an already-built local image:
python3 claude-post-tool-transient-disconnect.reproduce.py --skip-build
Complete self-contained reproducer: reports/claude-code/claude-post-tool-transient-disconnect.reproduce.py
Run from this repository checkout:
python3 reports/claude-code/claude-post-tool-transient-disconnect.reproduce.py
To reuse an already-built local image:
python3 reports/claude-code/claude-post-tool-transient-disconnect.reproduce.py --skip-build
Key output from a local run against the affected version:
provider_requests=1201
closed_mid_stream=1201
process_timed_out=True
REPRODUCED
The reproducer builds Claude Code from the public npm package and runs Docker with 2 CPUs and 4 GiB RAM by default.
Claude Model
Other
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.175
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Non-interactive/CI environment
Additional Information
The mock provider is local and deterministic; no external model call is required.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗