remotion-dev/remotion · error · Error

`reader` should not be provided to `${apiName}`. If you want

Error message

`reader` should not be provided to `${apiName}`. If you want to use it in the browser, use parseMediaOnWorker(). If you also want to read files from the file system, use parseMediaOnServerWorker().

What it means

parseMediaOnWorkerImplementation destructures {controller, reader, ...params} and immediately rejects if reader is truthy. The worker entry serializes options via postMessage, and a reader (with native handles / FS access) cannot cross the worker boundary. Browser workers use fetchReader implicitly; server FS reading needs the dedicated server worker.

Source

Thrown at packages/media-parser/src/parse-media-on-worker-entry.ts:114

		postOnVideoTrack: Boolean(onVideoTrack),
		// URL cannot be serialized, so we convert it to a string
		src: src instanceof URL ? src.toString() : src,
	};
};

const post = (worker: Worker, payload: WorkerRequestPayload) => {
	worker.postMessage(payload);
};

export const parseMediaOnWorkerImplementation = async <
	F extends Options<ParseMediaFields>,
>(
	{controller, reader, ...params}: ParseMediaOptions<F>,
	worker: Worker,
	apiName: string,
) => {
	if (reader) {
		throw new Error(
			`\`reader\` should not be provided to \`${apiName}\`. If you want to use it in the browser, use parseMediaOnWorker(). If you also want to read files from the file system, use parseMediaOnServerWorker().`,
		);
	}

	post(worker, convertToWorkerPayload(params));

	let workerTerminated = false;

	const {promise, resolve, reject} =
		withResolvers<ParseMediaResult<Options<ParseMediaFields>>>();

	const onAbort = () => {
		post(worker, {type: 'request-abort'});
	};

	const onResume = () => {
		post(worker, {type: 'request-resume'});
	};

View on GitHub (pinned to 78fe4bb3fd)

Solutions

  1. For browser worker parsing, drop the reader option (fetchReader is used automatically): call parseMediaOnWorker without reader.
  2. For FS-backed parsing in a worker, use parseMediaOnServerWorker() WITHOUT passing reader — it uses nodeReader internally.
  3. For FS-backed parsing on the main thread, call parseMedia({reader: nodeReader, ...}).
  4. Check that you are importing the right function for your environment.

Example fix

// before (wrong)
import {nodeReader} from '@remotion/media-parser/node-reader';
await parseMediaOnServerWorker({src, reader: nodeReader, fields: {}});

// after (right): server worker wires nodeReader itself
await parseMediaOnServerWorker({src, fields: {}});
// or, main thread:
await parseMedia({src, reader: nodeReader, fields: {}});
Defensive patterns

Strategy: validation

Validate before calling

// Never pass reader to worker variants; choose the right entry point
function pickParseFn({needsFs, inWorker}: {needsFs: boolean; inWorker: boolean}) {
  if (needsFs) return 'parseMediaOnServerWorker'; // uses nodeReader internally
  if (inWorker) return 'parseMediaOnWorker';
  return 'parseMedia';
}

Type guard

import type {ParseMediaOptions} from '@remotion/media-parser';
const optsHaveReader = (o: ParseMediaOptions<any>): boolean => Boolean((o as any).reader);

Try / catch

try {
  await parseMediaOnServerWorker({src, fields: {}});
} catch (e) {
  if (e instanceof Error && e.message.includes('`reader` should not be provided')) {
    // caller passed reader by mistake; strip it and retry
    throw new Error('Do not pass reader to worker variants');
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing `reader: nodeReader` (or any custom reader) to parseMediaOnWorker or parseMediaOnServerWorker. The API expects readers only on the main-thread parseMedia / parseMediaOnServer.

Common situations: Wanting FS access inside a worker and assuming reader should be passed through; migrating from parseMedia to a worker variant without dropping the reader option; copy-paste from a Node parseMedia call.

Related errors


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