{"record":{"id":"183271b0b09e1325","repo":"datawhalechina/hello-agents","slug":"error-183271","errorCode":null,"errorMessage":"浏览器不支持流式响应，无法获取研究进度","messagePattern":"浏览器不支持流式响应，无法获取研究进度","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"code/chapter14/helloagents-deepresearch/frontend/src/services/api.ts","lineNumber":42,"sourceCode":"    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\",\n      Accept: \"text/event-stream\"\n    },\n    body: JSON.stringify(payload),\n    signal: options.signal\n  });\n\n  if (!response.ok) {\n    const errorText = await response.text().catch(() => \"\");\n    throw new Error(\n      errorText || `研究请求失败，状态码：${response.status}`\n    );\n  }\n\n  const body = response.body;\n  if (!body) {\n    throw new Error(\"浏览器不支持流式响应，无法获取研究进度\");\n  }\n\n  const reader = body.getReader();\n  const decoder = new TextDecoder(\"utf-8\");\n  let buffer = \"\";\n\n  while (true) {\n    const { value, done } = await reader.read();\n    buffer += decoder.decode(value || new Uint8Array(), { stream: !done });\n\n    let boundary = buffer.indexOf(\"\\n\\n\");\n    while (boundary !== -1) {\n      const rawEvent = buffer.slice(0, boundary).trim();\n      buffer = buffer.slice(boundary + 2);\n\n      if (rawEvent.startsWith(\"data:\")) {\n        const dataPayload = rawEvent.slice(5).trim();\n        if (dataPayload) {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/code/chapter14/helloagents-deepresearch/frontend/src/services/api.ts#L24-L60","documentation":"Thrown by the helloagents-deepresearch frontend when the /research/stream response succeeded (resp.ok) but response.body is undefined — i.e. this browser/runtime cannot expose the response as a ReadableStream. Since the whole deep-research UX depends on incrementally reading SSE frames, the code refuses to continue rather than hang on a request() that never yields chunks.","triggerScenarios":"resp.ok is true and resp.body is undefined/null: old browsers (fetch streams shipped ~2017+), some WebViews/inline browsers, certain polyfilled fetch implementations (e.g. older whatwg-fetch) that lack body, or test environments (jsdom) without stream support.","commonSituations":"Users on legacy Chrome/Safari or in-app browsers; corporate environments replacing fetch with a polyfill; running the UI in jsdom-based tests; service-worker fetch interception stripping the body in old sw-toolbox versions.","solutions":["Confirm the runtime: log `'body' in Response.prototype` or typeof resp.body — if undefined, the environment lacks streaming fetch.","Upgrade/switch to a modern browser (Chrome 76+, Firefox 69+, Safari 14.1+ for mature ReadableStream responses).","If a legacy runtime must be supported, implement a non-streaming fallback endpoint (POST /research and poll or wait for the full JSON result).","In tests, polyfill ReadableStream (e.g. web-streams-polyfill) or mock fetch with a body-providing stub."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"export function supportsStreamingResponses(): boolean {\n  return typeof ReadableStream !== 'undefined'\n    && typeof Response !== 'undefined'\n    && 'body' in Response.prototype;\n}\n\nif (!supportsStreamingResponses()) {\n  useNonStreamingFallback(); // POST /research once, render final result\n}","typeGuard":"function hasReadableBody(resp: Response): resp is Response & { body: ReadableStream<Uint8Array> } {\n  return resp.body != null && typeof (resp.body as ReadableStream).getReader === 'function';\n}","tryCatchPattern":"if (!response.ok) { /* handled by error 25 path */ }\nif (!hasReadableBody(response)) {\n  renderStaticResult(await fetchFullResearch(payload));\n}","preventionTips":["Feature-detect ReadableStream responses at app start and disable/hide streaming-only UI in old runtimes.","Provide a non-streaming endpoint fallback for locked-down browsers.","In tests, polyfill ReadableStream (web-streams-polyfill) rather than mocking partial responses."],"tags":["browser-compat","streaming","readablestream","sse"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}