← All articles

Troubleshoot Claude Stream Idle Timeouts in UniRoute

Use UniRoute usage records and diagnostic summaries to investigate a Claude partial response, check charges and tool effects, and recover carefully.

UniRoute ·

If Claude Code stops with claude api error: stream idle timeout - partial response received while using UniRoute, preserve the partial answer and check the matching request in your UniRoute console before submitting again. This tutorial shows how to find that record, copy a diagnostic summary, distinguish an interrupted answer from a completed request, and decide what to do next.

The message alone does not tell you whether the client, network, gateway, or upstream stopped making progress. A timeout also does not establish zero consumption. Start with the request you already sent; you do not need another paid request to collect the information below.

1. Find the interrupted request in UniRoute

Open your UniRoute console and sign in to the account that owns the key used by Claude Code. In the usage records, choose a date range covering the incident and find the matching time and model. Include both successful and failed attempts in your review: one terminal action may have produced several requests.

Open View details for the relevant record and compare:

FieldHow to use it
Time and modelMatch the incident time, accounting for your timezone, and the exact model selected in the client.
Endpoint and request ID, when availableConfirm the request path and retain the identifier for private support. Keep gateway and upstream identifiers distinct.
Result, HTTP status, and redacted error responseRecord what the service observed; do not infer a missing status from the terminal message.
First token and duration, when availableCompare the request's recorded timing with when your terminal stopped. These are not a complete SSE event trace.
Input, output, cache, and actual cost, when availableReview the matching attempt and any retries individually. Missing fields remain unknown.

If no record matches, check the account, key, date range, model, and the actual destination configured in Claude Code. A request sent directly to Anthropic or through another gateway will not appear in your UniRoute account. Missing records do not prove the request was free or never reached a service.

In the request detail, choose Copy diagnostic summary. The summary includes safely recognized fields such as time, model, request ID, recorded HTTP status, and available cost. It excludes keys, prompts, response bodies, output links, and balances. Unavailable or unsafe fields are null; the summary does not confirm wallet settlement. Review the copied text and keep it for private support.

2. Confirm the client and the point where output stopped

Record claude --version, the model ID, and the configured destination. For a UniRoute setup, compare your local configuration with the Claude Code connection reference. Run /doctor inside Claude Code for its local setup checks; see official troubleshooting. A successful configuration check does not establish that the interrupted request completed.

Then write down what you actually saw:

ObservationNext check
No output appearedSeparate a connection or first-response delay from a later streaming interruption.
Some text appeared, then stoppedPreserve it; compare client timing with the matching record and any available network logs.
A tool call or result appearedInspect the changed files or external operation result before asking the agent to repeat work.
Text appeared complete, followed by an errorCheck whether another request started afterward; the displayed error may belong to a later round.
Only long tasks failCompare context size, output length, tool rounds, and observed limits, changing one factor at a time.

Do not paste credentials or entire configuration files into a public issue. A network proxy and an API provider are separate settings: a proxy carries traffic, while the provider determines the endpoint and authentication. Review the UniRoute endpoint reference if the actual destination is unclear.

3. Distinguish idle time from total duration

If you maintain an integration and can observe events, keep three timings separate: time until headers or the first event, the gap since the last received data, and total elapsed time. Your client's definition of “idle” may track bytes, complete events, or visible text. Those clocks can disagree.

For example, headers might arrive at 0.10 seconds, text at 0.45 seconds, and the last event at 1.00 seconds before the client stops at 1.25 seconds. These invented values explain measurement; they are not UniRoute or Claude Code defaults. The console's recorded first-token and duration fields cannot reconstruct every event in that timeline.

Under the Messages streaming protocol, message_stop ends a message; ping does not mean new answer text. An SSE error can occur after HTTP success, as described in the API error reference. EOF without the expected terminal event leaves the stream incomplete. Even a completed message may require another tool step to finish the user's task.

For your own parser, assemble complete SSE frames across network chunks. Do not execute a partial tool-input fragment. Only adjust a timeout after confirming that the installed client or intermediary reads the setting and that the observed timing justifies the change. A larger limit does not resolve every network or upstream failure.

4. Check effects and cost before a recovery attempt

Use the UniRoute record together with the local task state. Neither one alone establishes what an agent already changed.

StateBefore continuing
Request was rejected before outputRead the rejection, resolve the specific authentication, permission, rate, or service problem, and check whether another attempt ran.
Partial text with no tools observedKeep the partial reply. A new answer is a new request; limit its scope and spending.
Tool input or a tool result appearedReview file changes, command logs, and operation identifiers. Reconcile completed actions before requesting more work.
A deployment, payment, message, or other external write may have runLook up its result using a stable identifier. Keep an unknown outcome marked unknown instead of replaying it.
Final usage or actual cost is missingWait for records or ask private support to reconcile the request. Missing final usage does not mean zero cost.

Review client, SDK, wrapper, and gateway retry behavior. Use one owner and a finite attempt and elapsed-time budget when recovering from a confirmed transient failure. Do not add a repeating retry loop around an action that may already retry.

Check current UniRoute model and channel prices before another paid attempt. The Claude Code cost guide explains input, output, and cache costs. A client estimate or wallet balance difference cannot attribute one charge when several requests are active. If the incident was an HTTP 500 before streaming began, use the UniRoute error 500 workflow; if it was an HTTP 529 or mid-stream overloaded_error, see the Claude API 529 overloaded error guide.

If a small comparison is still useful after reconciliation, make it manually in a trusted empty directory with the intended provider, model, permissions, and hooks reviewed. Use a short nonsensitive prompt, run once, and check the resulting usage before continuing. It is a real request and can incur charges, including client retries; a short success does not validate a long task.

5. Send the UniRoute diagnostic summary to private support

Use Contact private support by email in the request detail, or send your reviewed summary to support@uniroute.app. Add these observations, since the copied service fields do not establish what happened in your terminal:

  • Client version, incident time with timezone, destination hostname, and exact model ID.
  • Whether there was no output, partial text, a tool call, or an apparently completed reply.
  • Known attempt count, observed timing, and whether an SSE error or terminal event was actually seen.
  • Reviewed tool effects and any one-variable comparison you already performed.

Keep missing information explicit. Exclude keys, authorization headers, cookies, prompts, private code, complete responses, account balances, and unrelated records. Keep request identifiers in private support rather than public posts. For requests handled by a different provider, use that provider's records and support channel.

Optional appendix: learn the stream boundaries locally

To examine the timing differences without an API key or a model charge, download the Python 3 local stream probe, inspect it, then run:

curl --fail --silent --show-error --proto '=https' \
  --output claude-stream-probe.py \
  https://uniroute.app/examples/claude-stream-probe.py
python3 claude-stream-probe.py --scenario all

The download uses the public website. The program then starts a temporary server on 127.0.0.1 and makes synthetic requests only to that loopback server. It accepts no real key or remote API URL and makes no model request. It demonstrates boundaries; it cannot diagnose your production incident or verify a UniRoute account.

ScenarioDemonstration
normalA stream reaches the terminal event.
sse-errorHTTP success is followed by an SSE error.
truncatedThe connection ends before completion.
idle-gapBody data pauses past the probe's idle limit.
delayed-first-eventHeaders arrive before a complete event.
ping-deadlineHeartbeats continue until a total deadline, without answer text.
fragmented-multilineNetwork chunks and multiline data need complete frame assembly.

Run python3 claude-stream-probe.py --scenario idle-gap for one case. Its optional --idle-timeout 0.2 --total-timeout 0.6 values are simulation seconds, not Claude Code settings. The probe defines idle as time without body bytes; ttfb_ms approximates time to complete headers and first_event_ms records the first complete SSE frame. In the delayed-first-event fixture, that field is null because the idle limit expires first. Read outcomes and timings together; the probe does not print response content or retry failures.