{"record":{"id":"9c16c01a4d99bd53","repo":"janhq/jan","slug":"response-body-is-null","errorCode":null,"errorMessage":"Response body is null","messagePattern":"Response body is null","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/llamacpp-extension/src/index.ts","lineNumber":3665,"sourceCode":"    }\n    const response = await fetch(url, {\n      method: 'POST',\n      headers,\n      body,\n      connectTimeout: Number(this.timeout) * 1000, // default 10 minutes\n      signal: combinedController.signal,\n    }).finally(() => clearTimeout(timeoutId))\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => null)\n      throw new Error(\n        `API request failed with status ${response.status}: ${JSON.stringify(\n          errorData\n        )}`\n      )\n    }\n\n    if (!response.body) {\n      throw new Error('Response body is null')\n    }\n\n    const reader = response.body.getReader()\n    const decoder = new TextDecoder('utf-8')\n    let buffer = ''\n    let jsonStr = ''\n    try {\n      while (true) {\n        const { done, value } = await reader.read()\n\n        if (done) {\n          break\n        }\n\n        buffer += decoder.decode(value, { stream: true })\n\n        // Process complete lines in the buffer\n        const lines = buffer.split('\\n')","sourceCodeStart":3647,"sourceCodeEnd":3683,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/extensions/llamacpp-extension/src/index.ts#L3647-L3683","documentation":"Thrown by handleStreamingResponse() when response.ok is true but response.body is null/undefined, so getReader() cannot proceed. Streaming inference requires a readable body; a 2xx with no body is a protocol violation by the server (or a runtime/proxy that swallowed the body). The check exists because reading a null body would throw a less informative TypeError further down.","triggerScenarios":"A reverse proxy (nginx/cloudflare) buffered or stripped the stream and returned 200 with empty body. The runtime's fetch implementation does not expose body for this response type. The router returned 204 No Content by mistake. A misconfigured middleware compressed/absorbed the SSE stream.","commonSituations":"Self-hosted behind a buffering proxy without proxy_buffering off / X-Accel-Buffering. WebKit/JavaScriptCore fetch quirks. Router version mismatch returning a non-streaming 200. Streaming was requested (opts.stream=true) but the upstream silently downgraded.","solutions":["If behind a proxy, disable buffering for the streaming route (e.g. nginx proxy_buffering off; add header X-Accel-Buffering: no).","Ensure opts.stream=true actually reaches the router and the router version supports SSE streaming.","Retry as a non-streaming request if the runtime/proxy cannot deliver a body.","Check the router logs - a 200 with empty body often indicates an upstream handler bug."],"exampleFix":"// before - proxy strips body\nconst s = await provider.chat({ ...opts, stream: true }, ac) // throws: body is null\n// after - fall back to non-streaming\nlet s\ntry { s = await provider.chat({ ...opts, stream: true }, ac) }\ncatch (e) {\n  if (/body is null/i.test(String(e))) { const r = await provider.chat({ ...opts, stream: false }, ac); /* use r */ return }\n  throw e\n}","handlingStrategy":"fallback","validationCode":"// Probe whether streaming is deliverable in this environment (optional)\n// Most callers cannot pre-check; instead catch and degrade to non-streaming.\nconst supportsStreamBody = typeof ReadableStream !== 'undefined'\nif (!supportsStreamBody && opts.stream) { console.warn('streaming not supported - downgrading'); opts.stream = false }","typeGuard":"// No static type guard; runtime check is on the response.\nfunction responseHasBody(r: Response): boolean { return r.body != null }","tryCatchPattern":"let result\ntry { result = await provider.chat({ ...opts, stream: true }, ac) }\ncatch (e) {\n  if (/body is null/i.test(String(e))) { result = await provider.chat({ ...opts, stream: false }, ac) }\n  else throw e\n}","preventionTips":["Disable proxy buffering on the streaming route (nginx: proxy_buffering off).","Add X-Accel-Buffering: no to SSE responses.","Provide a non-streaming fallback path in the client for environments that strip stream bodies."],"tags":["chat","streaming","http","proxy","runtime","protocol"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}