{"record":{"id":"8b5edfe9f25bde4e","repo":"janhq/jan","slug":"malformed-chunk","errorCode":null,"errorMessage":"Malformed chunk","messagePattern":"Malformed chunk","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"extensions/llamacpp-extension/src/index.ts","lineNumber":2465,"sourceCode":"        // Process complete lines in the buffer\n        const lines = buffer.split('\\n')\n        buffer = lines.pop() || '' // Keep the last incomplete line in the buffer\n\n        for (const line of lines) {\n          const trimmedLine = line.trim()\n          if (!trimmedLine || trimmedLine === 'data: [DONE]') {\n            continue\n          }\n\n          if (trimmedLine.startsWith('data: ')) {\n            jsonStr = trimmedLine.slice(6)\n          } else if (trimmedLine.startsWith('error: ')) {\n            jsonStr = trimmedLine.slice(7)\n            const error = JSON.parse(jsonStr)\n            throw new Error(error.message)\n          } else {\n            // it should not normally reach here\n            throw new Error('Malformed chunk')\n          }\n          try {\n            const data = JSON.parse(jsonStr)\n            const chunk = data as chatCompletionChunk\n\n            yield chunk\n          } catch (e) {\n            logger.error('Error parsing JSON from stream or server error:', e)\n            // re‑throw so the async iterator terminates with an error\n            throw e\n          }\n        }\n      }\n    } finally {\n      reader.releaseLock()\n    }\n  }\n","sourceCodeStart":2447,"sourceCodeEnd":2483,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/extensions/llamacpp-extension/src/index.ts#L2447-L2483","documentation":"Thrown when an SSE line from the llama.cpp server starts with neither 'data: ' nor 'error: ', so the stream parser cannot classify the chunk. The comment in the source notes this should not normally happen; it guards against protocol violations.","triggerScenarios":"The server emits an unexpected line in the SSE stream — non-standard keep-alive comments not filtered out, a proxy injecting HTML error pages into the stream, or a llama.cpp version changing its stream format.","commonSituations":"Reverse proxy or middleware intercepting the streaming response; mismatched server/extension versions with different SSE framing; corrupted stream due to network truncation combined with buffer mis-splitting.","solutions":["Inspect the raw chunk contents (log trimmedLine) to see what the server actually sent.","Check for proxies/load balancers altering the streaming response and bypass them.","Verify the llama.cpp server version matches what the extension expects.","Make the parser resilient: skip empty/comment lines (': keep-alive') instead of throwing."],"exampleFix":"// before\n} else {\n  throw new Error('Malformed chunk')\n}\n// after\n} else if (trimmedLine.length > 0 && !trimmedLine.startsWith(':')) {\n  throw new Error(`Malformed chunk: ${trimmedLine.slice(0, 100)}`)\n}","handlingStrategy":"validation","validationCode":"function isSseLine(line: string): boolean {\n  return line.startsWith('data: ') || line.startsWith('error: ') || line.startsWith(':') || line.length === 0\n}","typeGuard":"null","tryCatchPattern":"try {\n  for await (const chunk of stream) yield chunk\n} catch (e) {\n  if ((e as Error).message === 'Malformed chunk') {\n    logRawStreamForDebugging()\n    throw new Error('Incompatible llamacpp server or interfering proxy on SSE stream')\n  }\n  throw e\n}","preventionTips":["Bypass reverse proxies/load balancers when streaming, or configure them to pass SSE through unbuffered.","Keep the llama.cpp server and extension versions aligned.","Test the SSE endpoint directly with curl to compare raw output.","Log the offending line before throwing to ease diagnosis."],"tags":["streaming","sse","parsing","llamacpp"],"backgroundTag":"unexpected-response-shape","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}