{"record":{"id":"79896cef712c9781","repo":"oven-sh/bun","slug":"http2contentlengthmismatch","errorCode":"HTTP2ContentLengthMismatch","errorMessage":"HTTP2ContentLengthMismatch","messagePattern":"HTTP2ContentLengthMismatch","errorType":"error_code","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/http/error.rs","lineNumber":12,"sourceCode":"#[allow(non_camel_case_types)]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]\npub enum Error {\n    #[error(\"CompressionFailed\")]\n    CompressionFailed,\n    #[error(\"Aborted\")]\n    Aborted,\n    #[error(\"WriteFailed\")]\n    WriteFailed,\n    #[error(\"HTTP2RefusedStream\")]\n    HTTP2RefusedStream,\n    #[error(\"HTTP2ContentLengthMismatch\")]\n    HTTP2ContentLengthMismatch,\n    #[error(\"HTTP2FrameSizeError\")]\n    HTTP2FrameSizeError,\n    #[error(\"HTTP2ProtocolError\")]\n    HTTP2ProtocolError,\n    #[error(\"HTTP2FlowControlError\")]\n    HTTP2FlowControlError,\n    #[error(\"HTTP2EnhanceYourCalm\")]\n    HTTP2EnhanceYourCalm,\n    #[error(\"HTTP2HeaderListTooLarge\")]\n    HTTP2HeaderListTooLarge,\n    #[error(\"HTTP2StreamReset\")]\n    HTTP2StreamReset,\n    #[error(\"HTTP2GoAway\")]\n    HTTP2GoAway,\n    #[error(\"HTTP2CompressionError\")]\n    HTTP2CompressionError,\n    #[error(\"Timeout\")]","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/src/http/error.rs#L1-L30","documentation":"On stream completion, the raw count of HTTP/2 DATA bytes received does not equal the Content-Length announced in HEADERS (src/http/h2_client/ClientSession.rs:1243-1248; RFC 9113 §8.1.1 declares a mismatch malformed). The body handler clamps its counter at content_length, so this catches undershoot and overshoot (truncated or over-long bodies) and fails the request instead of delivering corrupt data.","triggerScenarios":"An h2 server (or intermediate proxy translating h1<->h2) sends a Content-Length that disagrees with the actual DATA frames — e.g. wrong content-length after body rewrites, gzip applied after length computation, or a proxy mangling chunked->content-length conversion. Also triggered by truncation where the peer half-closes early.","commonSituations":"MITM/corporate proxies that modify bodies (compression, script injection) without fixing content-length; buggy h2 origins behind envoy/nginx; responses corrupted by middleboxes; rare server bugs after a firmware update.","solutions":["Retry the request — a length bug on one response often does not recur; h2 will usually open a new stream/connection.","Test the URL with curl --http2 to confirm the origin itself is inconsistent (`curl -v --http2 url 2>&1 | grep -i content-length`).","If you control the server/proxy: ensure body transforms run before content-length is set, or use chunked/stream framing instead of fixed lengths.","Report to the endpoint owner if curl reproduces the mismatch — this is a server-side protocol violation."],"exampleFix":"// before\nconst data = await (await fetch(url)).json(); // HTTP2ContentLengthMismatch kills the parse\n// after: bounded retry for the malformed-response case\nasync function getJson(url, tries = 3) {\n  for (let i = 0; ; i++) {\n    try { return await (await fetch(url)).json(); }\n    catch (e) {\n      if (i >= tries - 1 || !String(e.message).includes('HTTP2ContentLengthMismatch')) throw e;\n      await Bun.sleep(100 * (i + 1));\n    }\n  }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"function isContentLengthMismatch(err) {\n  return /HTTP2ContentLengthMismatch/i.test(String(err?.message ?? err));\n}","tryCatchPattern":"async function fetchRetryMalformed(url, init, tries = 3) {\n  for (let i = 0; ;i++) {\n    try { return await fetch(url, init); }\n    catch (err) {\n      if (i >= tries - 1 || !isContentLengthMismatch(err)) throw err;\n      await Bun.sleep(100 * (i + 1));\n    }\n  }\n}","preventionTips":["Reproduce with `curl -v --http2 <url>` before assuming a client bug — this is a server-side protocol violation","If you operate the origin/proxy: never rewrite bodies after content-length is computed","Prefer streamed/chunked responses on origins that transform bodies"],"tags":["http","http2","protocol","content-length","network"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}