{"record":{"id":"aee88da6aada48bb","repo":"nodejs/node","slug":"content-range-mismatch","errorCode":null,"errorMessage":"Content-Range mismatch","messagePattern":"Content-Range mismatch","errorType":"exception","errorClass":"RequestRetryError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/handler/retry-handler.js","lineNumber":283,"sourceCode":"\n    // Checkpoint for resume from where we left it\n    if (this.headersSent) {\n      // Only Partial Content 206 supposed to provide Content-Range,\n      // any other status code that partially consumed the payload\n      // should not be retried because it would result in downstream\n      // wrongly concatenate multiple responses.\n      if (statusCode !== 206 && (this.start > 0 || statusCode !== 200)) {\n        throw new RequestRetryError('server does not support the range header and the payload was partially consumed', statusCode, {\n          headers,\n          data: { count: this.retryCount }\n        })\n      }\n\n      const contentRange = parseRangeHeader(headers['content-range'])\n      // If no content range\n      if (!contentRange) {\n        // We always throw here as we want to indicate that we entred unexpected path\n        throw new RequestRetryError('Content-Range mismatch', statusCode, {\n          headers,\n          data: { count: this.retryCount }\n        })\n      }\n\n      // Let's start with a weak etag check\n      if (this.etag != null && this.etag !== headers.etag) {\n        // We always throw here as we want to indicate that we entred unexpected path\n        throw new RequestRetryError('ETag mismatch', statusCode, {\n          headers,\n          data: { count: this.retryCount }\n        })\n      }\n\n      validatePartialResponseContentLength(headers, contentRange, statusCode, this.retryCount)\n\n      const { start, size, end = size ? size - 1 : null } = contentRange\n","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/handler/retry-handler.js#L265-L301","documentation":"Thrown by RetryHandler.onResponseStart during a retry resume when the resumed response is expected to carry a Content-Range header (it is a 206 or a 200 resuming from start>0) but parseRangeHeader returns null, i.e. the header is missing or unparseable. Without a Content-Range the handler cannot verify it is resuming from the correct byte offset.","triggerScenarios":"A resume request gets a 2xx response that lacks the Content-Range header, or carries a malformed Content-Range that parseRangeHeader cannot interpret.","commonSituations":"Servers that answer 200 to Range requests without Content-Range; intermediary proxies that strip Content-Range; misconfigured compression that removes the header; buggy origin returning partial content without metadata.","solutions":["Confirm the server returns a well-formed Content-Range header (e.g. 'bytes 1000-1999/5000') on ranged responses.","Disable transparent retry-resume for origins that do not send Content-Range.","Validate the header with curl -I -H 'Range: bytes=0-0' before relying on resume."],"exampleFix":"// before (relying on retry resume against an origin that strips Content-Range)\nclient = client.compose(interceptors.retry())\n\n// after\n// verify with: curl -r 0-0 -I https://example.com/file  (look for content-range)\n// if missing, drop the retry interceptor and fetch atomically:\nclient = baseClient","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await retryClient.request(opts) } catch (e) { if (e.code === 'UND_ERR_REQ_RETRY' && /Content-Range mismatch/.test(e.message)) { await baseClient.request(opts) } else throw e }","preventionTips":["Verify Content-Range presence on ranged responses (curl -I -H 'Range: bytes=0-0').","Drop the retry interceptor for origins that strip Content-Range.","Restart atomically when the header is missing."],"tags":["undici","http","retry","range","content-range","resume"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}