remotion-dev/remotion · error · TypeError

outputs must be an object.

Error message

outputs must be an object.

What it means

validateOptions for separateVideoLayers() checks that options.outputs, when provided, is a non-null object (and not an array). It maps foreground/base output targets by layer key, so a malformed outputs value would break per-layer validation and is rejected up front.

Source

Thrown at packages/video-matting/src/separate-video-layers.ts:176

	}

	const isBlob = typeof Blob !== 'undefined' && options.src instanceof Blob;
	const isUrl = options.src instanceof URL;
	if (typeof options.src !== 'string' && !isUrl && !isBlob) {
		throw new TypeError('src must be a string, URL, or Blob.');
	}

	if (typeof options.src === 'string' && options.src.length === 0) {
		throw new TypeError('src must not be an empty string.');
	}

	if (
		options.outputs !== undefined &&
		(!options.outputs ||
			typeof options.outputs !== 'object' ||
			Array.isArray(options.outputs))
	) {
		throw new TypeError('outputs must be an object.');
	}

	validateLayerOutputOptions({
		layer: 'base',
		output: options.outputs?.base,
	});
	validateLayerOutputOptions({
		layer: 'foreground',
		output: options.outputs?.foreground,
	});
	if (
		options.outputs?.base?.outputWritable !== undefined &&
		options.outputs.base.outputWritable ===
			options.outputs.foreground?.outputWritable
	) {
		throw new TypeError(
			'outputs.base and outputs.foreground must not use the same outputWritable.',
		);

View on GitHub (pinned to b2f4e34732)

Solutions

  1. Reshape to an object: { base: {...}, foreground: {...} }
  2. Remove outputs to use defaults (if base-only output is acceptable)
  3. Validate your loaded config's shape before calling

Example fix

// before
await separateVideoLayers({ src, outputs: [{ layer: 'base', outputPath: 'b.mp4' }] });
// after
await separateVideoLayers({ src, outputs: { base: { outputPath: 'b.mp4' } } });
Defensive patterns

Strategy: validation

Validate before calling

if (outputs !== undefined && (outputs === null || typeof outputs !== 'object' || Array.isArray(outputs))) throw new TypeError('outputs must be a plain object');

Type guard

const isOutputsObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);

Try / catch

try { await separateVideoLayers({ src, outputs }); } catch (e) { if (e instanceof TypeError && e.message.includes('outputs must be an object')) { /* reshape config */ } else throw e; }

Prevention

When it happens

Trigger: Passing outputs: ['base','foreground'] (an array of layer names); passing null; JSON config where outputs is a list instead of a map.

Common situations: Misreading the API as taking a list of layers; config file authored with the wrong shape; YAML/JSON schema drift.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09). Data as JSON: /api/errors/c4befa82da1d9e8c. Report an issue: GitHub.