remotion-dev/remotion · error · TypeError
outputs.${layer} cannot specify both outputTarget and output
Error message
outputs.${layer} cannot specify both outputTarget and outputWritable. What it means
A layer output may specify either outputTarget (built-in sink selection) or outputWritable (a custom WritableStream sink), but not both — they are conflicting ways to choose where bytes go. Specifying both raises this TypeError to avoid ambiguous output behavior.
Source
Thrown at packages/video-matting/src/separate-video-layers.ts:132
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.`,
);
}
if (output.outputWritable !== undefined) {
if (
typeof WritableStream === 'undefined' ||
!(output.outputWritable instanceof WritableStream)
) {
throw new TypeError(
`outputs.${layer}.outputWritable must be a WritableStream.`,
);
}
if (output.outputWritable.locked) {
throw new TypeError(
`outputs.${layer}.outputWritable must not already be locked.`,
);View on GitHub (pinned to b2f4e34732)
Solutions
- Remove outputTarget when you supply outputWritable (the writable takes over as the sink).
- Remove outputWritable when you want the built-in 'arraybuffer' or 'web-fs' target.
- When merging configs, delete conflicting keys instead of naively spreading.
Example fix
// before
outputs: {video: {outputTarget: 'arraybuffer', outputWritable: stream}}
// after
outputs: {video: {outputWritable: stream}} Defensive patterns
Strategy: validation
Validate before calling
if (out.outputTarget !== undefined && out.outputWritable !== undefined) throw new TypeError('choose either outputTarget or outputWritable'); Type guard
null
Try / catch
try { await separateVideoLayers(opts); } catch (e) { if (e instanceof TypeError && e.message.includes('both outputTarget and outputWritable')) { delete layerConfig.outputTarget; await separateVideoLayers(opts); } else throw e; } Prevention
- Pick one sink mechanism per layer
- When merging configs, delete outputTarget if outputWritable is set
- Document which key wins in your config schema
When it happens
Trigger: Calling separateVideoLayers({outputs: {video: {outputTarget: 'arraybuffer', outputWritable: myStream}}}).
Common situations: Merging default config (outputTarget) with user config (outputWritable) via object spread; adding outputWritable without removing the default outputTarget.
Related errors
- 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
- You have passed a volume below 0 to your <${component} /> co
- You have passed a playbackRate of type ${typeof props.playba
AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09).
Data as JSON: /api/errors/60d20a6032a32b73.
Report an issue: GitHub.