remotion-dev/remotion · error · Error
Range header (${requestedRange}) does not match content-rang
Error message
Range header (${requestedRange}) does not match content-range header (${parsedContentRange?.start}) What it means
validateContentRangeAndDetectIfSupported handles the numeric-range branch: when a number was requested, status is not 206, and parsedContentRange.start !== requestedRange, it throws unless requestedRange === 0 (which is treated as 'range not supported, serve everything'). The server's Content-Range start must match the byte offset the parser asked for.
Source
Thrown at packages/media-parser/src/readers/from-fetch.ts:67
statusCode,
}: {
requestedRange: number | [number, number];
parsedContentRange: ParsedContentRange | null;
statusCode: number;
}): {supportsContentRange: boolean} => {
if (statusCode === 206) {
return {supportsContentRange: true};
}
if (
typeof requestedRange === 'number' &&
parsedContentRange?.start !== requestedRange
) {
if (requestedRange === 0) {
return {supportsContentRange: false};
}
throw new Error(
`Range header (${requestedRange}) does not match content-range header (${parsedContentRange?.start})`,
);
}
if (
requestedRange !== null &&
typeof requestedRange !== 'number' &&
(parsedContentRange?.start !== requestedRange[0] ||
parsedContentRange?.end !== requestedRange[1])
) {
throw new Error(
`Range header (${requestedRange}) does not match content-range header (${parsedContentRange?.start})`,
);
}
return {supportsContentRange: true};
};
View on GitHub (pinned to 78fe4bb3fd)
Solutions
- Ensure the server/CDN correctly implements Range: respond 206 with Content-Range: bytes N-M/T matching the requested start.
- Test with curl: `curl -v -r 1000-2000 <url>` and confirm Content-Range starts at 1000.
- Disable any transform/compression that breaks range fidelity for media MIME types.
- Move the asset to a Range-compliant host (S3, R2, static CDN) if the origin cannot be fixed.
Example fix
// before: origin ignores Range start
res.set('Content-Range', `bytes 0-${end}/${total}`); // always 0
// after: honor requested start
res.status(206)
.set('Content-Range', `bytes ${start}-${end}/${total}`)
.set('Content-Length', String(end - start + 1));
fs.createReadStream(file, {start, end}).pipe(res); Defensive patterns
Strategy: validation
Validate before calling
// Verify Content-Range start matches the requested numeric offset
const r = await fetch(url, {headers: {Range: 'bytes=1000-'}});
const cr = r.headers.get('content-range'); // expect 'bytes 1000-.../...'
if (r.status !== 206 || !cr || !cr.startsWith('bytes 1000-')) {
throw new Error('Server did not honor numeric Range start');
} Try / catch
try {
await parseMedia({src: url, fields: {durationInSeconds: true}});
} catch (e) {
if (e instanceof Error && e.message.includes('does not match content-range')) {
throw new Error('Origin Range compliance issue (numeric start mismatch)');
}
throw e;
} Prevention
- Make origins 206 with a Content-Range start equal to the requested offset.
- Test with curl -v -r <start>- <url> and inspect Content-Range.
- Disable range-mangling middleware/CDN features for media.
- Use Range-compliant object storage for media hosting.
When it happens
Trigger: The parser requested `Range: bytes=N-` (N>0) and the server returned a Content-Range starting at a different offset (e.g. always 0, or a clamped/wrong start) with a 200-ish status. Indicates the server ignored or mis-answered the Range request.
Common situations: CDNs that clamp ranges, servers that always return the full file with a stale Content-Range header, load balancers rewriting ranges, or caches keyed incorrectly returning the wrong byte slice.
Related errors
- Cannot read media without it supporting the "Content-Range"
- Cannot read media ${src} without a content length. This is c
- Server returned status code ${res.status} for ${resolvedUrl}
- No body
- Failed to fetch ${src} (HTTP code: ${res.status})
AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12).
Data as JSON: /api/errors/86b2ce6f29999844.
Report an issue: GitHub.