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
- Provide an options object per layer, e.g. {outputs: {video: {outputTarget: 'arraybuffer'}}}.
- Move file paths/booleans into object fields like outputTarget or outputWritable.
- 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
- Validate the outputs object shape at config load time
- Never store file paths or booleans directly as layer values
- Use TypeScript types for the outputs option
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
- forceTranscode must be a boolean.
- onModelLoadProgress must be a function.
- Argument missing for parameter "frame"
- Argument passed for "frame" is not a number: ${frame}
- You have passed a volume of type ${typeof props.volume} to y
AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09).
Data as JSON: /api/errors/ff363a9eb885566a.
Report an issue: GitHub.