Troubleshooting

How to troubleshoot 502 Bad Gateway and stream disconnected

Locate LLM API's 502 Bad Gateway, stream disconnected, upstream connect error, and read timeouts using short request controls, non-streaming testing, SSE event logging, and hierarchical timeouts.

Updated on 2026-10-26Checked 2026-08-26Estimated reading time: 11 minutesApplies to OpenAI Compatible API, SSE streaming output, long context, Agent and reverse proxy
Configuration fields were checked against public documentation. Models, prices, and capabilities can change; verify current values in the console and live API responses.
Special topic: OpenAI Compatible API Access and Troubleshooting Center

502 Bad Gateway Indicates that the service acting as a gateway or proxy is not getting a valid response from the upstream.stream disconnected means the client did not receive a complete streamed result, possibly before the first event arrived. The two may be related, but the wording alone cannot distinguish a model, gateway, network, or client-timeout issue.

When Codex or Claude Code disconnects, compare short streaming and non-streaming requests using the same protocol. If both fail, check the key, model access and upstream. If only streaming fails, inspect SSE events, proxy buffering, read timeouts and idle connection limits.

How to fix stream disconnected before completion: bad gateway

This error describes both an incomplete stream and a gateway error; it does not confirm model degradation. Record the time, final request path, HTTP status code, and request ID, then identify the failure stage:

  • An HTTP 502 response with no SSE events: investigate the gateway and upstream first, retain the error body, and do not classify it as an SSE parsing failure.
  • HTTP 200 and some events followed by an error event or a closed connection: check the final event, read timeout, proxy buffering, and protocol completion conditions. HTTP 200 does not mean the task succeeded.
  • A short curl request using the same protocol succeeds but Codex or Claude Code fails: check the client version, actual protocol, tool calls, and context compaction. A successful Chat Completions request does not establish Responses or Messages compatibility.

The AIFast HK examples below use https://www.aifast.hk/v1 and a key created on that site. Copy model IDs from the same account's live catalog; do not mix in another site's keys, permissions, or billing configuration.

How to diagnose upstream response stream was interrupted

This message indicates an interrupted upstream response stream, but the wording alone does not identify which layer closed the connection. Preserve the structured error fields code and message, request ID and last event. Even if the error is upstream_stream_read_error, interpret it together with the HTTP status, received data and gateway logs; it does not by itself establish a model failure.

Interruption stage Evidence to preserve first Next step
Before any usable event HTTP status, Content-Type and redacted error body Rule out HTML error pages, empty responses and protocol mismatches
After partial output Last event type, timestamp and whether a tool has already executed Check read and idle timeouts; verify any side effects before replaying the task
At a fixed elapsed time Client total timeout, proxy idle timeout and elapsed time Compare logs across layers to distinguish a local diagnostic timeout from an upstream interruption

Claude Code: Streaming response ended before any complete data was received

The client did not receive a usable streaming result. The official Claude Code error reference explains that this condition triggers an attempt without streaming. An answer after Retrying without streaming only shows that the fallback completed, not that SSE is fixed. Verify the actual behavior against the client version and logs.

Confirm that the request uses a Messages-compatible endpoint, record the HTTP status and Content-Type, and check for parseable message events rather than HTML, an empty body or another protocol's JSON. Ask the gateway administrator to check for rewritten response headers or stream bodies. Do not disable TLS verification or change all proxy settings at once.

Do not add unlimited manual retries on top of automatic fallback. Compare request IDs and usage for each attempt: a failed stream is not necessarily free, and the warning alone does not prove duplicate charges. The Chat Completions examples below test only that protocol; validate Claude Code's Messages and Codex's Responses with their respective checklists.

What three things should I check first for a 502 or stream disconnected error?

Using the same key and model, send a short request and compare stream: false with stream: true, then record the request ID, the final SSE event, and the disconnect time. If a short non-streaming request also fails, check authentication, model access, and upstream status first. If only streaming fails, check SSE buffering, read timeouts, and proxy connections. If only long contexts fail, check context length, the overall task deadline, and the retry policy.

Use four sets of controls to quickly narrow down the scope

Keep the same Key and model, and only change one variable:

control A B What can be explained
Enter length 20 word short question real long context Only when long input fails, the context and timeout will be checked first.
streaming mode stream: false stream: true Only when streaming fails, check SSE and proxy buffering first.
client curl / SDK Cursor, Dify or Agent Only the client fails, check client timeout and resolution
Task type normal text Tool call or multiple rounds of Agent Only complex tasks failed, check the rounds, tools and total time

Start with one short-request comparison. Repeat only the relevant variables when reproducibility needs checking and the budget allows. Record the time, status, request ID and interruption point; one result does not establish long-term health. Real requests may incur charges. Use a temporary limited key and remove keys, cookies and business content before sharing logs.

Run non-streaming short requests first

Set locally: AIFAST_API_KEY, and replace the model placeholder with an ID available to your account that supports Chat Completions. Both examples use the same short input and differ only in streaming mode. The 10-second connection limit and 60-second total limit are diagnostic parameters, not a platform SLA or universal production settings for long tasks.

(
: "${AIFAST_API_KEY:?First set a temporary limited Key}"
curl -q -sS -i --connect-timeout 10 --max-time 60 \
  https://www.aifast.hk/v1/chat/completions \
  -H "Authorization: Bearer $AIFAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Model copied from consoleID",
    "messages": [{"role": "user", "content": "Reply with only ok"}],
    "stream": false
  }'
curl_status=$?
printf '\ncurl_exit=%s\n' "$curl_status"
exit "$curl_status"
)
  • Short requests are also stable 502: save the request ID and time, check the platform or upstream status;
  • Short requests succeed and long requests fail: gradually shorten the context and increase the read timeout;
  • Non-streaming success, streaming failure: enter SSE check;
  • curl succeeds, application fails: check client, proxy and SDK configuration.

Check if SSE flow is complete

Use -N disables curl's own output buffering; it does not disable buffering in the server or intermediary proxies:

(
: "${AIFAST_API_KEY:?First set a temporary limited Key}"
curl -q -sS -i -N --connect-timeout 10 --max-time 60 \
  https://www.aifast.hk/v1/chat/completions \
  -H "Authorization: Bearer $AIFAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Model copied from consoleID",
    "messages": [{"role": "user", "content": "Reply with only ok"}],
    "stream": true
  }'
curl_status=$?
printf '\ncurl_exit=%s\n' "$curl_status"
exit "$curl_status"
)

curl_exit=0 only means that the transfer triggered no curl error, not that HTTP succeeded or the model task completed. Check the response status, protocol completion events and error body.curl_exit=28 means a timeout condition was reached. A cutoff at 60 seconds in this example may simply be the local total limit; it does not establish a platform outage.-q is the first argument to prevent personal curl configuration from adding retries or other options.

Key observations:

  1. Do you continue to receive data: event;
  2. Whether data events can be parsed according to the current protocol (excluding completion markers such as[DONE] );
  3. Whether a normal end tag appears;
  4. Whether to return an error event before interrupting;
  5. Whether the reverse proxy buffered or compressed the stream.

For a more complete client example and proxy check seeStreaming output and SSE access tutorial.

Completion conditions differ across the three protocols

Protocol Key completion signal Checks that must not be mixed
Chat Completions data: [DONE], interpreted alongside finish reasons and errors [DONE] is not ordinary JSON; a completion marker does not replace checking the complete content
Responses response.completed, with the final response status checked; handle failed or incomplete events separately Do not require [DONE] or count response.failed as successful
Anthropic Messages Complete content blocks and the final message_delta、message_stop Do not treat content_block_stop or ping as successful completion of the entire message

Even after a completion event, check for refusals, truncation, tool requests, and actual task completion. In-stream error events must be recorded separately. Missing final usage must not be treated as zero tokens or zero cost.

Split timeouts into three layers

Don’t just set a general timeout=30:

timeout function Common mismatches
Connection timeout Establish a TCP/TLS connection The setting is too long, and the network failure continues to fail.
Read timeout Wait for the next response fragment The setting is too short and the inference or tool phase is accidentally killed.
total task time Limit complete business tasks There is no upper limit, the Agent can run indefinitely

Long inferences and tool calls may wait longer between two text shards, but this does not mean that the total time limit should increase indefinitely. Reasonable read timeout and business deadline should be set respectively.

Codex or Claude Code reports stream disconnected

Long-running Codex and Claude Code tasks involve more than plain text streaming. They may depend on incremental tool arguments, tool-result round trips, context compaction, and session continuity. A successful short chat does not prove the complete agent workflow.

Retest in the following order:

  1. Pin the client version, Base URL, and model ID, then reuse the same read-only task.
  2. Start with a short non-streaming request to verify authentication, the model, and the base endpoint.
  3. Next, run a streaming request without tools and save the complete SSE event stream.
  4. Finally, run one read-only tool call and verify the incremental tool arguments, finish reason, and returned tool result.
  5. If the stream disconnects only after context compaction, save the last event received, the session length, and the client logs instead of only increasing the timeout.

For Codex, also verify the Responses API and its streaming events. For Claude Code, verify the Anthropic Messages compatibility endpoint. See the corresponding checklists Codex Gateway Checklist and Claude Code Gateway Checklist.

Reverse proxy key checks

If there is Nginx, Cloudflare, Lucky or other proxies in front of the application, check:

  • Whether response buffering inappropriate for SSE is turned off;
  • Whether the upstream read timeout is shorter than the client;
  • Whether to forward completely Authorization and Content-Type;
  • Whether the response was incorrectly compressed, spliced, or cached;
  • Whether the long connection is closed early due to idle timeout;
  • Whether the request body size limit is smaller than the real context.

Don't start by enlarging all timeouts and request body limits at the same time. First, confirm which layer is triggered by short request, long request and streaming comparison.

502 How to retry

Only do limited retries for requests that can be safely repeated, and add jitter. Be especially cautious in the following situations:

  • Asynchronous tasks such as drawing pictures and videos may have been created successfully;
  • Tool calls may have written to the database or sent messages;
  • Part of the content has been output to the user before the streaming request is interrupted;
  • The server has deducted the fee but the client has not received a complete response.

For tasks with side effects, idempotent keys, task IDs, or business deduplication mechanisms should be used. When you cannot determine whether the server is executing, do not reinitiate it directly.

Acceptance criteria for repair completion

  • Short requests and real contexts have been verified multiple times respectively;
  • Both non-streaming and streaming can end normally;
  • The log retains the request ID, interruption time, first fragment and last fragment time;
  • Responsibilities for connection, reading and total task time limit are clear;
  • The proxy does not buffer SSE or close long connections early;
  • The number of retries is limited, and tasks with side effects have a deduplication mechanism.

If exceptions continue to occur at the same entry, you can runModel Quality CheckSave the agreement and behavior report, then clickAPI comparison test templateRetest from the same region, model, and question set. Test reports are used to locate compatibility issues and are not equivalent to vendor identity certification or long-term SLA.

FAQ

How do you fix stream disconnected in Codex or Claude Code?

First fix the client version, Base URL, and model, then compare one short non-streaming request with one streaming request using the same key. If only streaming fails, check SSE parsing, proxy buffering, read timeouts, and idle timeouts first; do not retry indefinitely.

Are 502 Bad Gateway and stream disconnected the same problem?

No. A 502 means the gateway did not receive a valid upstream response. Stream disconnected means the client did not receive a complete streamed result, possibly before the first event arrived. If short requests also fail, check authentication, permissions, and upstream health first. Investigate SSE and the proxy chain when only streaming fails.

Why does a basic request succeed while an SSE streaming request fails?

A basic request verifies only the complete response; it does not prove that streaming events, termination markers, or proxy long connections work. Use curl -N to save data events, then check proxy buffering, read timeouts, and the normal termination marker.

Source checked

Reference and Check Sources

Next step

Test the current API before fixing, migrating, or creating a test key

Use a temporary, limited key to inspect model declarations, token fields, SSE, and tool calls. Review current models and pricing only when you need a replacement API.

Model Quality CheckModel PricingCreate Account