nodejs/node · error · RequestRetryError
server does not support the range header and the payload was
Error message
server does not support the range header and the payload was partially consumed
What it means
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.
Source
Thrown at deps/undici/src/lib/handler/retry-handler.js:273
const err = new RequestRetryError('Request failed', statusCode, {
headers,
data: {
count: this.retryCount
}
})
this.onResponseStartWithRetry(controller, statusCode, headers, statusMessage, err)
return
}
// Checkpoint for resume from where we left it
if (this.headersSent) {
// Only Partial Content 206 supposed to provide Content-Range,
// any other status code that partially consumed the payload
// should not be retried because it would result in downstream
// wrongly concatenate multiple responses.
if (statusCode !== 206 && (this.start > 0 || statusCode !== 200)) {
throw new RequestRetryError('server does not support the range header and the payload was partially consumed', statusCode, {
headers,
data: { count: this.retryCount }
})
}
const contentRange = parseRangeHeader(headers['content-range'])
// If no content range
if (!contentRange) {
// We always throw here as we want to indicate that we entred unexpected path
throw new RequestRetryError('Content-Range mismatch', statusCode, {
headers,
data: { count: this.retryCount }
})
}
// Let's start with a weak etag check
if (this.etag != null && this.etag !== headers.etag) {
// We always throw here as we want to indicate that we entred unexpected pathView on GitHub (pinned to 1b2de5e052)
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.
Example fix
// before
agent.dispatch({ ..., headers: { range: 'bytes=1000-' } }, retryHandler)
// after
// server does not support Range -> do not use the retry interceptor; restart on failure
async function download(opts) {
for (let attempt = 0; ; attempt++) {
try { return await fetchFully(opts) }
catch (e) { if (attempt >= 3) throw e }
}
} Defensive patterns
Strategy: retry
Try / catch
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 } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/f48dae07b5bcda55.
Report an issue: GitHub.