remotion-dev/remotion · error · Error

No moov box found

Error message

No moov box found

What it means

Thrown by getMoovAtom after fetching and parsing the tail of the file (from endOfMdat to contentLength) when none of the parsed top-level boxes is a moov-box. This means the second fetch did not contain the movie metadata — the file either has no moov at all (unplayable), or the fetch read the wrong byte range, or the response was empty/truncated.

Source

Thrown at packages/media-parser/src/containers/iso-base-media/get-moov-atom.ts:134

			onlyIfMdatAtomExpected: null,
			contentLength: state.contentLength - endOfMdat,
		});
		if (box.type === 'box') {
			boxes.push(box.box);
		}

		if (iterator.counter.getOffset() + endOfMdat > state.contentLength) {
			throw new Error('Read past end of file');
		}

		if (iterator.counter.getOffset() + endOfMdat === state.contentLength) {
			break;
		}
	}

	const moov = boxes.find((b) => b.type === 'moov-box');
	if (!moov) {
		throw new Error('No moov box found');
	}

	Log.verbose(
		state.logLevel,
		`Finished fetching moov atom in ${Date.now() - start}ms`,
	);

	return moov;
};

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. Confirm the file actually contains a moov atom using `ffprobe` or `mp4info`.
  2. Ensure your readerInterface correctly serves the requested byte range; test with curl: `curl -r <endOfMdat>-<contentLength> -o tail.bin <url>` and inspect.
  3. If moov is missing, re-mux with `-movflags faststart` so moov sits at the head and no second fetch is needed.
  4. Provide an accurate contentLength; an under-sized length will exclude moov from the fetched window.

Example fix

// before
await parseMedia({ src: url });

// after
// Ensure moov is at the front so no second fetch is needed
// On the authoring side:
//   ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4
// Then parse normally
await parseMedia({ src: `${url}?v=faststart` });
Defensive patterns

Strategy: validation

Validate before calling

import {execFileSync} from 'node:child_process';
function fileHasMoov(file: string): boolean {
  try {
    execFileSync('ffprobe', ['-v', 'error', '-show_format', file], {encoding: 'utf8'});
    return true;
  } catch { return false; }
}

Type guard

import type {IsoBaseMediaBox} from './base-media-box';
function boxesContainMoov(boxes: IsoBaseMediaBox[]): boolean {
  return boxes.some((b) => b.type === 'moov-box');
}

Try / catch

try {
  await parseMedia({ src: url });
} catch (err) {
  if (/^No moov box found$/i.test(String(err?.message))) {
    throw new Error('No moov atom in the file. Re-mux with ffmpeg -movflags faststart or confirm the byte range served.');
  }
  throw err;
}

Prevention

When it happens

Trigger: Reached in the second-fetch branch (no m3u8 header segment). After reading bytes [endOfMdat, contentLength) and walking top-level boxes, no 'moov-box' was found. Common when contentLength is wrong so the parser reads a window that does not include moov, when the server ignored the range request, or when the file genuinely lacks moov.

Common situations: Files where moov is not at the end (e.g. at the head with ftyp) but the parser still did a second fetch because the first pass did not see it. Truncated uploads missing moov entirely. CDN/range-request misbehavior returning the wrong slice. moov atom stripped by accident.

Related errors


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