{"id":"630fba689810138e","repo":"sindresorhus/got","slug":"err-http-content-length-mismatch","errorCode":"ERR_HTTP_CONTENT_LENGTH_MISMATCH","errorMessage":"Content-Length mismatch: expected ${this._expectedContentLength} bytes, received ${actualSize} bytes","messagePattern":"Content-Length mismatch: expected (.+?) bytes, received (.+?) bytes","errorType":"exception","errorClass":"ReadError","httpStatus":null,"severity":"error","filePath":"source/core/index.ts","lineNumber":900,"sourceCode":"\t\t(this._requestOptions as (NativeRequestOptions & {_alpnSocket?: Socket}) | undefined)?._alpnSocket?.destroy();\n\t}\n\n\tprivate _shouldIncrementallyDecodeBody(): boolean {\n\t\tconst {responseType, encoding} = this.options;\n\n\t\treturn Boolean(this._noPipe)\n\t\t\t&& (responseType === 'text' || responseType === 'json')\n\t\t\t&& isUtf8Encoding(encoding)\n\t\t\t&& typeof globalThis.TextDecoder === 'function';\n\t}\n\n\tprivate _checkContentLengthMismatch(): boolean {\n\t\tif (this.options.strictContentLength && this._expectedContentLength !== undefined) {\n\t\t\t// Use compressed bytes count when available (for compressed responses),\n\t\t\t// otherwise use _downloadedSize (for uncompressed responses)\n\t\t\tconst actualSize = this._compressedBytesCount ?? this._downloadedSize;\n\t\t\tif (actualSize !== this._expectedContentLength) {\n\t\t\t\tthis._beforeError(new ReadError({\n\t\t\t\t\tmessage: `Content-Length mismatch: expected ${this._expectedContentLength} bytes, received ${actualSize} bytes`,\n\t\t\t\t\tname: 'Error',\n\t\t\t\t\tcode: 'ERR_HTTP_CONTENT_LENGTH_MISMATCH',\n\t\t\t\t}, this));\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate async _finalizeBody(): Promise<void> {\n\t\tconst {options} = this;\n\t\tconst headers = options.getInternalHeaders();\n\n\t\tconst isForm = !is.undefined(options.form);\n\t\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\t\tconst isJSON = !is.undefined(options.json);","sourceCodeStart":882,"sourceCodeEnd":918,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/index.ts#L882-L918","documentation":"Produced at source/core/index.ts:900 by `_checkContentLengthMismatch`. When `strictContentLength` is true (the default) and the server sent a Content-Length header, got tracks the actual bytes received (`_compressedBytesCount` for compressed responses, `_downloadedSize` otherwise). If those numbers diverge, got emits a ReadError with code ERR_HTTP_CONTENT_LENGTH_MISMATCH. This mirrors Node's own validation: a mismatch means the response body was truncated or padded, so any parsed body is unreliable.","triggerScenarios":"Server closes the connection mid-body (truncated response); proxy or CDN miscounts bytes; compression layer (gzip/br/zstd) sends a Content-Length that doesn't match the compressed payload; server streams chunks and mis-declares the total length; client uses `decompress: false` so the raw byte count is compared against a Content-Length that was meant for the decompressed body.","commonSituations":"Flaky upstream that drops connections, reverse proxies that rewrite bodies without updating Content-Length, Brotli/zstd-compressed responses behind an HTTP/1 proxy, or disabling decompression while strictContentLength is on. Also seen when a server uses chunked transfer-encoding but also sets Content-Length.","solutions":["Retry the request — the underlying cause is almost always a transient connection drop, and got's default retry will catch ECONNRESET but you may need to add ERR_HTTP_CONTENT_LENGTH_MISMATCH to retry.errorCodes.","If you intentionally disable decompression (`decompress: false`), also set `strictContentLength: false` because the raw byte count will not match a Content-Length that describes the decompressed payload.","Verify the upstream server/proxy is sending a correct Content-Length (or omitting it in favor of Transfer-Encoding: chunked) for compressed payloads."],"exampleFix":"// before — strict content-length check on a compressed body you don't decompress\nawait got('https://api', { decompress: false });\n\n// after — relax the check when intentionally reading raw bytes\nawait got('https://api', { decompress: false, strictContentLength: false });","handlingStrategy":"retry","validationCode":"// Configure retry to cover the mismatch code, and relax strictContentLength when reading raw bytes.\nconst options = {\n  strictContentLength: !decompressDisabled, // set false when decompress: false\n  retry: { limit: 3, errorCodes: ['ERR_HTTP_CONTENT_LENGTH_MISMATCH', 'ECONNRESET'] }\n};","typeGuard":null,"tryCatchPattern":"import {HTTPError} from 'got';\n\ntry {\n  await got(url, { retry: { limit: 3 } });\n} catch (error) {\n  if (error instanceof Error && (error as any).code === 'ERR_HTTP_CONTENT_LENGTH_MISMATCH') {\n    // transient truncation — got may have already retried; surface to caller for decision\n    throw new Error('Response body was truncated (Content-Length mismatch). Retry upstream.', { cause: error });\n  }\n  throw error;\n}","preventionTips":["Include 'ERR_HTTP_CONTENT_LENGTH_MISMATCH' in retry.errorCodes for flaky upstreams.","If you set decompress: false, also set strictContentLength: false — raw bytes won't match a decompressed Content-Length.","Verify upstream servers/proxies send a correct Content-Length (or use chunked transfer-encoding) for compressed payloads."],"tags":["content-length","compression","network","read-error"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}