{"record":{"id":"7a0e39b699e582e6","repo":"danielmiessler/Fabric","slug":"stream-content-error","errorCode":"STREAM_CONTENT_ERROR","errorMessage":"value.content","messagePattern":"value\\.content","errorType":"exception","errorClass":"ChatError","httpStatus":null,"severity":"error","filePath":"web/src/lib/services/ChatService.ts","lineNumber":291,"sourceCode":"\t): Promise<ReadableStream<StreamResponse>> {\n\t\tconst request = await this.createChatRequest(userInput, systemPromptText);\n\t\treturn this.fetchStream(request);\n\t}\n\n\tpublic async processStream(\n\t\tstream: ReadableStream<StreamResponse>,\n\t\tonContent: (content: string, response?: StreamResponse) => void,\n\t\tonError: (error: Error) => void,\n\t): Promise<void> {\n\t\tconst reader = stream.getReader();\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (value.type === \"error\") {\n\t\t\t\t\tthrow new ChatError(value.content, \"STREAM_CONTENT_ERROR\");\n\t\t\t\t}\n\n\t\t\t\tif (value.type === \"content\") {\n\t\t\t\t\tonContent(value.content, value);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tonError(\n\t\t\t\terror instanceof ChatError\n\t\t\t\t\t? error\n\t\t\t\t\t: new ChatError(\"Stream processing error\", \"STREAM_ERROR\", error),\n\t\t\t);\n\t\t} finally {\n\t\t\treader.releaseLock();\n\t\t}\n\t}\n}\n","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/lib/services/ChatService.ts#L273-L309","documentation":"While consuming the /api/chat stream, a chunk with { type: 'error', content } makes the reader throw ChatError(content, 'STREAM_CONTENT_ERROR'). The HTTP layer was fine; the backend reported an error mid-stream — typically a failure calling the upstream LLM provider after headers were already sent.","triggerScenarios":"Long generations where the vendor API disconnects or rate-limits after the stream began; model context overflow surfacing mid-stream; provider timeout after first tokens; backend panic serialized as an error event.","commonSituations":"Ollama model OOM-ing on large contexts; API rate limit hit mid-generation; network drop between backend and LLM vendor while the browser-backend connection stays open.","solutions":["Log the value.content of the error event — it carries the backend's upstream error text","If rate-limit/timeout related, add retry with backoff for streams that fail after partial output","Reduce context size or split the request if the upstream rejects it mid-generation"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isStreamContentError(e: unknown): e is ChatError & { code: 'STREAM_CONTENT_ERROR' } {\n  return e instanceof ChatError && e.code === 'STREAM_CONTENT_ERROR';\n}","tryCatchPattern":"try {\n  await chatService.processStream(stream, onContent, onError);\n} catch (e) {\n  if (isStreamContentError(e)) {\n    keepPartialOutput(); // content already delivered is still valid\n    showStreamErrorMessage(e.message);\n  } else throw e;\n}","preventionTips":["Preserve partial assistant output when a stream dies mid-flight","Show the backend's error event text to the user — it names the upstream cause","Cap context size to reduce mid-generation provider failures"],"tags":["streaming","chat","llm-provider","mid-stream-error"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}