remotion-dev/remotion · error · TypeError
outputs.${layer}.outputWritable must be a WritableStream.
Error message
outputs.${layer}.outputWritable must be a WritableStream. What it means
separateVideoLayers() validates each layer's output options. When you pass outputs.<layer>.outputWritable, it must be an actual Web WritableStream instance; anything else (a Node.js stream, a string path, a plain object) is rejected with this TypeError because the library pipes MediaRecorder/WebCodecs output into it via the standard streams API.
Source
Thrown at packages/video-matting/src/separate-video-layers.ts:142
`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.`,
);
}
}
};
const validateOptions = (options: SeparateVideoLayersOptions) => {
if (!options || typeof options !== 'object') {
throw new TypeError('separateVideoLayers() expects an options object.');
}
const isBlob = typeof Blob !== 'undefined' && options.src instanceof Blob;View on GitHub (pinned to b2f4e34732)
Solutions
- Pass a Web WritableStream, e.g. new WritableStream({...}) or one obtained from a TransformStream
- If you have a Node stream, wrap/convert it to a Web WritableStream (e.g. node:stream/web Writable.toWeb(nodeStream))
- Remove the outputWritable property entirely so the library uses its default output handling
- Ensure the runtime supports web streams (Node >= 18, modern browsers)
Example fix
// before
await separateVideoLayers({ src: 'video.mp4', outputs: { base: { outputWritable: fs.createWriteStream('base.mp4') } } });
// after
import { Writable } from 'node:stream/web';
await separateVideoLayers({ src: 'video.mp4', outputs: { base: { outputWritable: Writable.toWeb(fs.createWriteStream('base.mp4')) } } }); Defensive patterns
Strategy: type-guard
Validate before calling
function assertWritable(s) { if (s !== undefined && !(typeof WritableStream !== 'undefined' && s instanceof WritableStream)) throw new TypeError('outputWritable must be a Web WritableStream'); } Type guard
const isWritableStream = (v) => typeof WritableStream !== 'undefined' && v instanceof WritableStream;
Try / catch
try { await separateVideoLayers(opts); } catch (e) { if (e instanceof TypeError && e.message.includes('outputWritable must be a WritableStream')) { /* fix stream construction */ } else throw e; } Prevention
- Only pass Web WritableStream instances (browser or node:stream/web)
- Convert Node streams with Writable.toWeb()
- Never pass file paths where a stream is expected
When it happens
Trigger: Passing outputs.base.outputWritable or outputs.foreground.outputWritable set to a Node stream (fs.createWriteStream), a file path string, null (non-undefined), a WritableStream-like duck-typed object, or running in an environment without WritableStream defined (old Node/runtime without web streams).
Common situations: Confusing Node.js fs write streams with Web WritableStreams in SSR/Node scripts; passing a file path instead of a stream; forgetting to import WritableStream from a polyfill in older runtimes; reusing a writable that was already handed to another consumer.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Output paths must be strings.
- outputs.${layer}.outputWritable must not already be locked.
- src must be a string, URL, or Blob.
- outputs must be an object.
- outputs.base and outputs.foreground must not use the same ou
AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09).
Data as JSON: /api/errors/073884a4b0493747.
Report an issue: GitHub.