{"record":{"id":"f201422b0042b964","repo":"datawhalechina/hello-agents","slug":"resp-status-f20142","errorCode":null,"errorMessage":"智能体流式请求失败: ${resp.status}","messagePattern":"智能体流式请求失败: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Co-creation-projects/usernamedadad-AutoFlow/frontend/src/services/api.js","lineNumber":56,"sourceCode":"        onEvent({ eventType, data: parsed });\n      } catch {\n        onEvent({ eventType, data: { type: \"error\", message: \"SSE 解析失败\" } });\n      }\n    }\n  }\n\n  return remaining;\n}\n\nexport async function streamAgentChat(payload, onEvent) {\n  const resp = await fetch(`${API_BASE}/api/agent/chat/stream`, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify(payload),\n  });\n\n  if (!resp.ok || !resp.body) {\n    throw new Error(`智能体流式请求失败: ${resp.status}`);\n  }\n\n  const reader = resp.body.getReader();\n  const decoder = new TextDecoder(\"utf-8\");\n  let buffer = \"\";\n\n  while (true) {\n    const { value, done } = await reader.read();\n    if (done) break;\n    buffer += decoder.decode(value, { stream: true });\n    buffer = parseSSEChunk(buffer, onEvent);\n  }\n}\n","sourceCodeStart":38,"sourceCodeEnd":70,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/usernamedadad-AutoFlow/frontend/src/services/api.js#L38-L70","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","Verify VITE_API_BASE_URL and that the backend registers POST /api/agent/chat/stream with SSE support (Content-Type: text/event-stream).","If behind nginx, disable proxy buffering for this route: `proxy_buffering off;` and set `X-Accel-Buffering: no` on the response.","Inspect the Network tab response for the failing request to see the server's error body.","Split the guard so each failure has its own message (see exampleFix)."],"exampleFix":"// before\nif (!resp.ok || !resp.body) {\n  throw new Error(`智能体流式请求失败: ${resp.status}`);\n}\n\n// after\nif (!resp.ok) {\n  const detail = await resp.text().catch(() => \"\");\n  throw new Error(`智能体流式请求失败: ${resp.status} ${detail.slice(0, 200)}`);\n}\nif (!resp.body) {\n  throw new Error(\"响应不包含可读流（代理可能缓冲或吞掉了 SSE 响应）\");\n}","handlingStrategy":"try-catch","validationCode":"const supportsStreams = typeof ReadableStream !== 'undefined' && 'body' in Response.prototype;\nif (!supportsStreams) {\n  throw new Error('当前浏览器不支持流式响应');\n}\nif (!payload || typeof payload !== 'object') {\n  throw new Error('聊天请求体无效');\n}","typeGuard":"function isSSEFetchResponse(resp: Response): resp is Response & { body: ReadableStream<Uint8Array> } {\n  return resp.ok && resp.body instanceof ReadableStream;\n}","tryCatchPattern":"try {\n  await streamAgentChat(payload, onEvent);\n} catch (err) {\n  if (/200|流/.test((err as Error).message)) {\n    // body/stream lost — proxy buffering or non-streaming response\n    disableProxyBuffering();\n  } else {\n    showChatError((err as Error).message);\n  }\n}","preventionTips":["Set proxy_buffering off (or X-Accel-Buffering: no) on every SSE route in front of the backend.","Feature-detect response streaming before offering the agent chat UI.","Keep the SSE endpoint returning text/event-stream and never wrap it in buffering middleware."],"tags":["http","sse","streaming","fetch","proxy-config"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}