Troubleshooting

API Returns 200 but No Text? A Streaming Troubleshooting Guide

An API request can return HTTP 200 while your application ends up with no answer. For a streaming response, check both the text events and the final outcome before reporting success. Start with a small text-only request and keep the HTTP status separate from the result your user actually received.

Identify the response format first

This guide covers the Responses API event format. OpenAI's streaming documentation describes text deltas and a separate completion event. A parser written for Chat Completions chunks is not a substitute for a Responses event handler.

Before debugging the parser, record the client version, selected protocol, request path and response Content-Type. Confirm the endpoint format in the LLMAPI documentation. The API setup tool can help check URL formatting; it does not prove that a key or model will work.

Check these three outcomes separately

Use three questions when inspecting a failing request:

  1. Did the HTTP connection return the expected status and response format?
  2. Did the application receive any output text?
  3. Did the response finish successfully, fail, or stop before completion?

For Responses streams, watch response.output_text.delta, response.completed and response.failed, as well as error events. Avoid marking a response successful just because a text fragment arrived. Likewise, a completed response with no text should not automatically become an empty chat answer: inspect whether the response contains another output type that your application needs to handle.

Reproduce the application bug without a live key

The following Python example is a deliberately small test for a single text-only Responses output. It handles already-decoded event dictionaries, not raw HTTP or SSE framing. It is not a general SDK replacement, and intentionally rejects empty text, failed responses and streams that end early.

def completed_text(events):
    pieces = []
    for event in events:
        kind = event.get("type")
        if kind == "response.output_text.delta":
            pieces.append(event["delta"])
        elif kind in ("response.failed", "error"):
            raise RuntimeError("Response did not finish successfully")
        elif kind == "response.completed":
            text = "".join(pieces)
            if not text.strip():
                raise RuntimeError("Completed without text; inspect output types")
            return text
    raise RuntimeError("Stream ended before completion")

events = [
    {"type": "response.output_text.delta", "delta": "Hello"},
    {"type": "response.completed"},
]
assert completed_text(events) == "Hello"

Remove the last event and the same test must raise an error. Replace it with response.failed and the earlier text must not turn the request into a success. Add an empty completion-only case to confirm that your text-only user interface does not silently display a blank answer.

These are synthetic regression cases, not measurements of a live model or a claim about every compatible API. A production client should use a protocol-aware SDK and handle multiple output items, tool calls, cancellation and incomplete responses explicitly.

Narrow the failure with one controlled request

For a real failing integration, use a short prompt that asks for a plain sentence. Initially leave out images, tools and a long conversation. Compare a streaming request with an otherwise equivalent non-streaming request, if the endpoint supports both. A difference gives you a useful lead, not proof of which component is broken.

If text events arrived but nothing was displayed, inspect your event dispatch and output assembly. If the stream ended before a completion event, preserve that outcome as an interruption. If an explicit error arrived, inspect its code before changing the client configuration. Avoid repeated automatic retries while you are still establishing what happened.

Save useful evidence without saving credentials

A support report should include the timestamp and timezone, client version, model ID, protocol, request path, HTTP status, request ID when supplied, and the last event type. State whether any text arrived and whether the same small request works without streaming.

Remove authorization headers, API keys, cookies and private prompt content before sharing logs. Keep partial output separate from a completed answer so the next person can distinguish a display bug from an interrupted request. For endpoint and client configuration, return to the client integration guides.

分享这篇文章

开始使用 LLM API

免费套餐可用。Claude Code 一行配置。

免费开始