{"record":{"id":"de2b757816c7af8c","repo":"datawhalechina/hello-agents","slug":"error-de2b75","errorCode":null,"errorMessage":"服务响应中断，请重试","messagePattern":"服务响应中断，请重试","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/usernamedadad-AutoFlow/frontend/src/App.jsx","lineNumber":243,"sourceCode":"              });\n            }\n            pushChatMessage(modeKey, {\n              role: \"assistant\",\n              content: data.mermaid_code || \"\",\n              kind: \"code\",\n              title: ASSISTANT_PREFIX[modeKey],\n            });\n          }\n\n          if (data.type === \"error\") {\n            settled = true;\n            setError(data.message || \"智能体执行失败\");\n          }\n        }\n      );\n\n      if (!settled) {\n        throw new Error(\"服务响应中断，请重试\");\n      }\n    } finally {\n      setThinkingMap((prev) => ({ ...prev, [modeKey]: false }));\n    }\n  };\n\n  const handleGenerate = async () => {\n    setLoading(true);\n    setError(\"\");\n    setStatusText(\"请求处理中...\");\n\n    try {\n      if (mode === \"plan\") {\n        await runPlanMode();\n      } else if (mode === \"code\") {\n        await runCodeMode();\n      } else {\n        await runAgentMode();","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/usernamedadad-AutoFlow/frontend/src/App.jsx#L225-L261","documentation":"Thrown by runAgentMode in AutoFlow's frontend after streamAgentChat completes without ever receiving a terminal SSE event. The stream loop only sets settled=true on data.type === 'result' or 'error'; if the server closes the connection, the proxy drops it, or the stream emits only non-terminal 'status' frames, settled stays false and this generic interruption error is raised. It is a client-side liveness check over a server-sent-events chat stream, not a backend exception.","triggerScenarios":"Calling streamAgentChat (POST to the agent chat endpoint with mode/prompt/direction) where the backend: crashes mid-run, times out after only emitting {'type':'status'} frames, is restarted during generation, or returns 200 but closes the body early. Also triggered if the SSE parser silently swallows malformed frames so the result event is never parsed.","commonSituations":"Long LLM generations exceeding reverse-proxy (nginx/Vite dev proxy) read timeouts; backend container OOM-killed mid-stream; dev server hot-reload dropping the EventSource/fetch stream; backend returning NDJSON lines the client parser cannot recognize; network switch mid-request on mobile.","solutions":["Check backend logs for the crashed/timed-out agent run and re-run the same prompt; the error is transient whenever the backend died mid-stream.","Raise proxy read timeouts (e.g. nginx proxy_read_timeout, Vite server.proxy timeout) above the agent's worst-case generation time.","Make the backend always emit a terminal frame: catch-all exception handler that writes {'type':'error','message':...} before closing the response.","Add heartbeats/keepalive 'status' frames plus an explicit 'done' sentinel event so the client can distinguish slow progress from a dead stream.","Implement exponential-backoff retry in runAgentMode when this error fires (idempotency-safe since no result was delivered)."],"exampleFix":"// before\nif (!settled) {\n  throw new Error(\"服务响应中断，请重试\");\n}\n\n// after\nif (!settled) {\n  // distinguish network drop from backend error; allow auto-retry\n  throw new StreamInterruptedError(\"服务响应中断，请重试\", { retryable: true });\n}\n// caller: catch (e) { if (e.retryable && attempt < 2) return runAgentMode(attempt + 1); setError(e.message); }","handlingStrategy":"retry","validationCode":"// Before streaming, confirm the endpoint is alive so dead-backend cases\n// surface as a clear network error instead of a silent empty stream.\nasync function checkStreamEndpoint(url) {\n  const res = await fetch(url, { method: 'HEAD' });\n  if (!res.ok) throw new Error(`endpoint ${url} unreachable: ${res.status}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await streamAgentChat(payload, onEvent);\n  if (!settled) throw new Error('服务响应中断，请重试');\n} catch (e) {\n  if (isTransient(e) && attempt < MAX_RETRIES) {\n    await backoff(attempt); // 1s, 2s, 4s\n    return run(attempt + 1);\n  }\n  setError(e.message || '请求失败');\n}","preventionTips":["Require the backend to always terminate the stream with a result or error event (contract test this).","Add a client-side idle timer: if no event arrives in N seconds, abort and retry instead of waiting for stream close.","Set proxy read timeouts above worst-case generation time in every environment."],"tags":["frontend","react","streaming","sse","network","timeout"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}