remotion-dev/remotion · error · TypeError

outputs.${layer} must be an object.

Error message

outputs.${layer} must be an object.

What it means

In separateVideoLayers(), each entry of the outputs option is validated by validateLayerOutputOptions. A per-layer output must be an object (or undefined); passing a primitive, string, null, or an array raises this TypeError naming the offending layer key.

Source

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

const throwIfAborted = (signal: AbortSignal | undefined) => {
	if (signal?.aborted) {
		throw createAbortError(signal);
	}
};

const validateLayerOutputOptions = ({
	layer,
	output,
}: {
	layer: 'base' | 'foreground';
	output: VideoLayerOutputOptions | undefined;
}) => {
	if (output === undefined) {
		return;
	}

	if (!output || typeof output !== 'object' || Array.isArray(output)) {
		throw new TypeError(`outputs.${layer} must be an object.`);
	}

	if (
		output.outputTarget !== undefined &&
		output.outputTarget !== 'arraybuffer' &&
		output.outputTarget !== 'web-fs'
	) {
		throw new TypeError(
			`outputs.${layer}.outputTarget must be arraybuffer or web-fs.`,
		);
	}

	if (
		output.outputTarget !== undefined &&
		output.outputWritable !== undefined
	) {
		throw new TypeError(
			`outputs.${layer} cannot specify both outputTarget and outputWritable.`,

View on GitHub (pinned to b2f4e34732)

Solutions

  1. Provide an options object per layer, e.g. {outputs: {video: {outputTarget: 'arraybuffer'}}}.
  2. Move file paths/booleans into object fields like outputTarget or outputWritable.
  3. Omit the layer key entirely instead of passing null when no output is wanted.

Example fix

// before
await separateVideoLayers({input, outputs: {video: 'out.mp4'}});
// after
await separateVideoLayers({input, outputs: {video: {outputTarget: 'arraybuffer'}}});
Defensive patterns

Strategy: type-guard

Validate before calling

const isLayerOutput = (o: unknown): boolean => o === undefined || (!!o && typeof o === 'object' && !Array.isArray(o));
Object.entries(outputs).forEach(([k, v]) => { if (!isLayerOutput(v)) throw new TypeError('outputs.' + k + ' must be an object'); });

Type guard

const isLayerOutput = (o: unknown): o is LayerOutputOptions | undefined => o === undefined || (!!o && typeof o === 'object' && !Array.isArray(o));

Try / catch

try { await separateVideoLayers(opts); } catch (e) { if (e instanceof TypeError && e.message.startsWith('outputs.')) { console.error('bad outputs config:', e.message); } throw e; }

Prevention

When it happens

Trigger: Calling separateVideoLayers({outputs: {video: true}}), outputs: {audio: 'file.mp4'}, outputs: {fg: []}, or outputs: {bg: null}.

Common situations: Config built from JSON where a layer is set to a string path or boolean flag; mistaking outputs for a flat record of file names; spreading arrays into outputs.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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