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:
- Do you continue to receive
data:event; - Whether data events can be parsed according to the current protocol (excluding completion markers such as
[DONE]); - Whether a normal end tag appears;
- Whether to return an error event before interrupting;
- 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:
- Pin the client version, Base URL, and model ID, then reuse the same read-only task.
- Start with a short non-streaming request to verify authentication, the model, and the base endpoint.
- Next, run a streaming request without tools and save the complete SSE event stream.
- Finally, run one read-only tool call and verify the incremental tool arguments, finish reason, and returned tool result.
- 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
AuthorizationandContent-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.