{"record":{"id":"9bfdfde7654bc8df","repo":"janhq/jan","slug":"response-body-is-null-9bfdfd","errorCode":null,"errorMessage":"Response body is null","messagePattern":"Response body is null","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/mlx-extension/src/index.ts","lineNumber":456,"sourceCode":"        )\n      }\n    }\n    const response = await fetch(url, {\n      method: 'POST',\n      headers,\n      body,\n      signal: combinedController.signal,\n    }).finally(() => clearTimeout(timeoutId))\n\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => null)\n      throw new Error(\n        `MLX API request failed with status ${response.status}: ${JSON.stringify(errorData)}`\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\n    try {\n      while (true) {\n        const { done, value } = await reader.read()\n        if (done) break\n\n        buffer += decoder.decode(value, { stream: true })\n\n        const lines = buffer.split('\\n')\n        buffer = lines.pop() || ''\n\n        for (const line of lines) {\n          const trimmedLine = line.trim()","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/janhq/jan/blob/fad3f12a147d138388a66f0d92a02b2675f65294/extensions/mlx-extension/src/index.ts#L438-L474","documentation":"Thrown by handleStreamingResponse() right after a successful (OK) fetch, when response.body is null. The HTTP layer returned a 2xx but no readable stream body, so SSE parsing cannot proceed. This is a runtime/transport anomaly rather than a server rejection.","triggerScenarios":"An opaque response (type 'opaque'/'opaqueredirect') whose body is null; a fetch polyfill or environment (some WebKit/JSC builds) that does not expose body for streaming; a misconfigured fetch that consumed the body before this check; a response with Content-Length but no body stream.","commonSituations":"Running under a runtime where Response.body is unsupported; a service worker/proxy returning an empty body; the body was accidentally read elsewhere; CORS opacity stripping the body.","solutions":["Ensure the fetch runs in an environment with full ReadableStream support (not an opaque response).","Avoid consuming response.body/json before reaching the stream reader.","If the runtime lacks body, fall back to non-streaming chat and parse the full JSON.","Check that no proxy intercepts and re-wraps the response without a body."],"exampleFix":"// before\nif (!response.body) throw new Error('Response body is null')\nconst reader = response.body.getReader()\n\n// after\nif (!response.body) {\n  logger.warn('Streaming body null; falling back to non-stream parse')\n  const data = (await response.json()) as chatCompletion\n  return (async function* () { yield toChunk(data) })()\n}\nconst reader = response.body.getReader()","handlingStrategy":"fallback","validationCode":"// verify runtime exposes streaming bodies before requesting stream\nconst supportsBody = typeof Response !== 'undefined' && 'body' in Response.prototype\nif (!supportsBody) opts.stream = false // request non-streaming instead","typeGuard":"function hasReadableBody(r: Response): r is Response & { body: ReadableStream<Uint8Array> } {\n  return r.body != null && typeof (r.body as any).getReader === 'function'\n}","tryCatchPattern":"try {\n  return yield* engine.chat({ ...opts, stream: true }, abort)\n} catch (e) {\n  if (/Response body is null/.test(String(e))) {\n    // fall back to non-streaming\n    const full = (await engine.chat({ ...opts, stream: false }, abort)) as chatCompletion\n    return full\n  }\n  throw e\n}","preventionTips":["Run in an environment with full ReadableStream support.","Do not consume response.body before the stream reader.","Provide a non-streaming fallback when body is unavailable."],"tags":["http","streaming","runtime","fetch","mlx","typescript"],"backgroundTag":null,"analyzedSha":"fad3f12a147d138388a66f0d92a02b2675f65294","analyzedAt":"2026-08-12T20:33:47.516Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}