{"record":{"id":"f48dae07b5bcda55","repo":"nodejs/node","slug":"server-does-not-support-the-range-header-and-the-p","errorCode":null,"errorMessage":"server does not support the range header and the payload was partially consumed","messagePattern":"server does not support the range header and the payload was partially consumed","errorType":"exception","errorClass":"RequestRetryError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/handler/retry-handler.js","lineNumber":273,"sourceCode":"      const err = new RequestRetryError('Request failed', statusCode, {\n        headers,\n        data: {\n          count: this.retryCount\n        }\n      })\n\n      this.onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err)\n      return\n    }\n\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","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/handler/retry-handler.js#L255-L291","documentation":"Thrown by RetryHandler.onResponseStart during a retry resume when headers were already sent to the downstream handler (partial body consumed) and the new response is neither 206 nor a clean 200-from-start. Resuming mid-body from anything other than a proper partial-content response would concatenate incompatible bodies, so the handler refuses to retry and surfaces the underlying status code.","triggerScenarios":"A retry is attempted after part of the body was consumed, but the server responds with 200 (ignoring Range) while start > 0, or with an error status like 416/500; the handler cannot safely stitch the responses together.","commonSituations":"Servers/CDNs that ignore Range headers and replay the full body; origin returning 416 Range Not Satisfiable after a transient failure; object storage that does not support ranged GETs on certain object types.","solutions":["Ensure the origin honors Range requests and returns 206 with a correct Content-Range on resume.","For endpoints that do not support Range, disable transparent retry-resume (remove the retry interceptor for those routes).","Restart the download from byte 0 on failure instead of relying on resume."],"exampleFix":"// before\nagent.dispatch({ ..., headers: { range: 'bytes=1000-' } }, retryHandler)\n\n// after\n// server does not support Range -> do not use the retry interceptor; restart on failure\nasync function download(opts) {\n  for (let attempt = 0; ; attempt++) {\n    try { return await fetchFully(opts) }\n    catch (e) { if (attempt >= 3) throw e }\n  }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await retryClient.request(opts) } catch (e) { if (e.code === 'UND_ERR_REQ_RETRY' && /range header and the payload was partially consumed/.test(e.message)) { await baseClient.request(opts) /* no retry-resume */ } else throw e }","preventionTips":["Confirm the origin answers ranged GETs with 206.","Disable retry-resume for endpoints that return 200 to Range.","Restart downloads from byte 0 when resume is unsupported."],"tags":["undici","http","retry","range","partial-content","resume"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}