{"record":{"id":"1e2bb149da843b71","repo":"danielmiessler/Fabric","slug":"null-response","errorCode":"NULL_RESPONSE","errorMessage":"Response body is null","messagePattern":"Response body is null","errorType":"exception","errorClass":"ChatError","httpStatus":null,"severity":"error","filePath":"web/src/lib/services/ChatService.ts","lineNumber":79,"sourceCode":"\t\t\t);\n\n\t\t\tconst response = await fetch(\"/api/chat\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify(request),\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new ChatError(\n\t\t\t\t\t`HTTP error! status: ${response.status}`,\n\t\t\t\t\t\"HTTP_ERROR\",\n\t\t\t\t\t{ status: response.status },\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst reader = response.body?.getReader();\n\t\t\tif (!reader) {\n\t\t\t\tthrow new ChatError(\"Response body is null\", \"NULL_RESPONSE\");\n\t\t\t}\n\n\t\t\treturn this.createMessageStream(reader);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ChatError) throw error;\n\t\t\tthrow new ChatError(\"Failed to fetch chat stream\", \"FETCH_ERROR\", error);\n\t\t}\n\t}\n\n\t/**\n\t * Clean up pattern output for display. Should only be called on complete/accumulated content,\n\t * never on individual streaming tokens (which have leading spaces as word separators).\n\t */\n\tpublic cleanPatternOutput(content: string): string {\n\t\t// Remove markdown fence if present\n\t\tlet cleaned = content.replace(/^```markdown\\n/, \"\");\n\t\tcleaned = cleaned.replace(/\\n```$/, \"\");\n","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/lib/services/ChatService.ts#L61-L97","documentation":"ChatError('Response body is null', 'NULL_RESPONSE') fires when POST /api/chat returned 2xx but response.body is null so no reader can be obtained. In practice on the web platform this almost always indicates an opaque/filtered response or a consumed body rather than a genuinely empty successful reply.","triggerScenarios":"A service worker or proxy returning an opaque response for /api/chat; the Response object being reused after body consumption; a runtime without fetch streaming support.","commonSituations":"PWA/service worker caching interfering with POST /api/chat; older browser or webview lacking ReadableStream on responses; test environment mocking fetch without a body.","solutions":["Disable any service worker / PWA caching for /api/chat POSTs and retest","Check navigator/browsed environment supports response.body (evergreen browsers, not legacy webviews)","If mocking fetch in tests, make the mock return a real ReadableStream"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (typeof ReadableStream === 'undefined') {\n  throw new Error('This browser does not support streaming responses');\n}","typeGuard":"function isNullResponseError(e: unknown): boolean {\n  return e instanceof ChatError && e.code === 'NULL_RESPONSE';\n}","tryCatchPattern":"try { stream = await chatService.sendMessage(request); }\ncatch (e) {\n  if (isNullResponseError(e)) { /* bypass service worker / retry without SW */ }\n  else throw e;\n}","preventionTips":["Exclude POST /api/chat from service-worker caching","Never consume the chat Response body before handing it to ChatService"],"tags":["streaming","fetch","service-worker","chat"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}