remotion-dev/remotion · error · Error

Cannot read media ${src} without a content length. This is c

Error message

Cannot read media ${src} without a content length. This is currently not supported. Ensure the media has a "Content-Length" HTTP header.

What it means

After the initial readerInterface.read, internalParseMedia checks contentLength. The fetch reader derives contentLength from the Content-Length HTTP header; if it is null the parser throws because seek/range logic, progress reporting, and the infinite-loop guard all depend on a known total length. HLS (.m3u8) and .ts endpoints can live without it, but ordinary HTTP media cannot.

Source

Thrown at packages/media-parser/src/internal-parse-media.ts:81

	const prefetchCache = new Map<string, ReturnType<typeof makeFetchRequest>>();

	const {
		reader: readerInstance,
		contentLength,
		name,
		contentType,
		supportsContentRange,
		needsContentRange,
	} = await readerInterface.read({
		src,
		range: null,
		controller,
		logLevel,
		prefetchCache,
	});

	if (contentLength === null) {
		throw new Error(
			`Cannot read media ${src} without a content length. This is currently not supported. Ensure the media has a "Content-Length" HTTP header.`,
		);
	}

	if (!supportsContentRange && needsContentRange) {
		throw new Error(
			'Cannot read media without it supporting the "Content-Range" header. This is currently not supported. Ensure the media supports the "Content-Range" HTTP header.',
		);
	}

	const hasAudioTrackHandlers = Boolean(onAudioTrack);
	const hasVideoTrackHandlers = Boolean(onVideoTrack);

	const state = makeParserState({
		hasAudioTrackHandlers,
		hasVideoTrackHandlers,
		controller,
		onAudioTrack: onAudioTrack ?? null,

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Configure the origin/CDN to send Content-Length for media assets (disable dynamic compression for media MIME types, or serve pre-compressed/static files).
  2. Serve files statically (Content-Length is set automatically for static file responses) instead of through a streaming script.
  3. If you control the server, set Content-Length explicitly when streaming a known-size file.
  4. For Node, use the nodeFileSystemReader (reader: nodeReader) which reads the file size from the FS instead of HTTP.

Example fix

// before: server omits Content-Length
app.get('/video', (req, res) => fs.createReadStream(path).pipe(res));

// after: send Content-Length and support ranges
const stat = fs.statSync(path);
res.status(200)
  .set('Content-Length', String(stat.size))
  .set('Accept-Ranges', 'bytes')
  .set('Content-Type', 'video/mp4');
fs.createReadStream(path).pipe(res);
Defensive patterns

Strategy: validation

Validate before calling

// Probe headers before parsing to confirm Content-Length is present
const head = await fetch(url, {method: 'GET', headers: {Range: 'bytes=0-0'}});
if (!head.headers.get('content-length')) {
  throw new Error('Server omits Content-Length; cannot parse via fetchReader');
}

Try / catch

try {
  await parseMedia({src: url, fields: {durationInSeconds: true}});
} catch (e) {
  if (e instanceof Error && e.message.includes('without a content length')) {
    // switch to a nodeReader-backed parse or fix the origin
    throw new Error('Origin must send Content-Length for media');
  }
  throw e;
}

Prevention

When it happens

Trigger: Fetching media over HTTP where the server omits Content-Length (chunked transfer-encoding, compressed on the fly, or a proxy that strips the header). Reached on the very first read in internalParseMedia when contentLength comes back null for a non-.m3u8/.ts resource.

Common situations: CDN/proxy (Cloudflare, nginx with gzip/brotli dynamic compression, Server-Sent-Events endpoints) stripping Content-Length; serving from an S3 presigned URL with chunked encoding; legacy streaming servers; localhost dev servers using chunked responses.

Related errors


AI-assisted analysis of remotion-dev/remotion@78fe4bb3fd (2026-08-12). Data as JSON: /api/errors/924f83be0bd662fb. Report an issue: GitHub.