datawhalechina/hello-agents · error

智能体流式请求失败: ${resp.status}

Error message

智能体流式请求失败: ${resp.status}

What it means

Thrown by streamAgentChat() in the AutoFlow frontend when POST /api/agent/chat/stream either returns a non-2xx status OR succeeds without a readable body (resp.body falsy). Because the check is `!resp.ok || !resp.body`, the message's status code can even be 200 while the real failure is a missing streaming body. SSE streaming requires both an accepted request and a ReadableStream-capable response.

Source

Thrown at Co-creation-projects/usernamedadad-AutoFlow/frontend/src/services/api.js:56

        onEvent({ eventType, data: parsed });
      } catch {
        onEvent({ eventType, data: { type: "error", message: "SSE 解析失败" } });
      }
    }
  }

  return remaining;
}

export async function streamAgentChat(payload, onEvent) {
  const resp = await fetch(`${API_BASE}/api/agent/chat/stream`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });

  if (!resp.ok || !resp.body) {
    throw new Error(`智能体流式请求失败: ${resp.status}`);
  }

  const reader = resp.body.getReader();
  const decoder = new TextDecoder("utf-8");
  let buffer = "";

  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    buffer = parseSSEChunk(buffer, onEvent);
  }
}

View on GitHub (pinned to 606a07d341)

Solutions

  1. Distinguish the two causes: log resp.status — non-2xx means a server-side rejection; 200 with this error means the body/stream was lost (usually proxy buffering or a non-streaming response).
  2. Verify VITE_API_BASE_URL and that the backend registers POST /api/agent/chat/stream with SSE support (Content-Type: text/event-stream).
  3. If behind nginx, disable proxy buffering for this route: `proxy_buffering off;` and set `X-Accel-Buffering: no` on the response.
  4. Inspect the Network tab response for the failing request to see the server's error body.
  5. Split the guard so each failure has its own message (see exampleFix).

Example fix

// before
if (!resp.ok || !resp.body) {
  throw new Error(`智能体流式请求失败: ${resp.status}`);
}

// after
if (!resp.ok) {
  const detail = await resp.text().catch(() => "");
  throw new Error(`智能体流式请求失败: ${resp.status} ${detail.slice(0, 200)}`);
}
if (!resp.body) {
  throw new Error("响应不包含可读流(代理可能缓冲或吞掉了 SSE 响应)");
}
Defensive patterns

Strategy: try-catch

Validate before calling

const supportsStreams = typeof ReadableStream !== 'undefined' && 'body' in Response.prototype;
if (!supportsStreams) {
  throw new Error('当前浏览器不支持流式响应');
}
if (!payload || typeof payload !== 'object') {
  throw new Error('聊天请求体无效');
}

Type guard

function isSSEFetchResponse(resp: Response): resp is Response & { body: ReadableStream<Uint8Array> } {
  return resp.ok && resp.body instanceof ReadableStream;
}

Try / catch

try {
  await streamAgentChat(payload, onEvent);
} catch (err) {
  if (/200|流/.test((err as Error).message)) {
    // body/stream lost — proxy buffering or non-streaming response
    disableProxyBuffering();
  } else {
    showChatError((err as Error).message);
  }
}

Prevention

When it happens

Trigger: POST /api/agent/chat/stream with the chat payload returns 4xx/5xx (validation error, agent backend down, missing route), or returns 200 but the response has no body — e.g. a proxy that buffers/empties the stream, a 204-style empty response, or an intermediary stripping the stream. Also fires when VITE_API_BASE_URL misroutes the request.

Common situations: Dev proxy or nginx buffering SSE and closing the body; CORS preflight failure making resp.ok false; backend returning JSON error with 500 before any stream starts; browsers/environments (older WebView) without fetch streaming where resp.body is undefined even on 200.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/f201422b0042b964. Report an issue: GitHub.