remotion-dev/remotion · error · Error
Video layer output was canceled
Error message
Video layer output was canceled
What it means
Thrown by finalize() in create-video-layer-output when the mediabunny output finished finalizing but a cancellation had been requested in the meantime. The library checks cancellationRequested after each async step of finalization so it never hands back output from an aborted render. It signals that the caller canceled the layer output (or something in the pipeline did) while finalize() was in flight.
Source
Thrown at packages/video-matting/src/create-video-layer-output.ts:220
})();
return cancellationPromise;
};
const finalize = (): Promise<VideoLayerOutput> => {
if (cancellationRequested) {
return Promise.reject(new Error('Video layer output was canceled'));
}
if (finalizationPromise !== null) {
return finalizationPromise;
}
finalizationPromise = (async () => {
try {
await output.finalize();
if (cancellationRequested) {
throw new Error('Video layer output was canceled');
}
const mimeType = await output.getMimeType();
if (cancellationRequested) {
throw new Error('Video layer output was canceled');
}
await closeOutputWritable();
if (cancellationRequested) {
throw new Error('Video layer output was canceled');
}
finalized = true;
if (outputMode === 'writable') {
return {
dispose: () => Promise.resolve(),
getBlob: () =>View on GitHub (pinned to b2f4e34732)
Solutions
- Await the cancel() promise and treat finalize()'s rejection as expected — do not retry finalize after cancel
- Restructure so cancel() and finalize() are not called concurrently; finalize first, then cancel only on error
- Guard with the returned finalizationPromise so only one lifecycle call runs per output
- Check output.state before calling finalize; skip finalize if the output was canceled
Example fix
// before
const out = await layerOutput.finalize();
// after
try {
const out = await layerOutput.finalize();
} catch (e) {
if (wasCanceled) return; // cancel() was invoked, rejection is expected
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (typeof layerOutput.cancel === 'function') {
// ensure no cancel() is pending before finalizing
}
Type guard
const canFinalize = (o: {isCanceled?: () => boolean}) => !o.isCanceled?.();
Try / catch
try {
await layerOutput.finalize();
} catch (e) {
if ((e as Error).message === 'Video layer output was canceled') return;
throw e;
}
Prevention
- Never call cancel() and finalize() concurrently on the same output
- Track a generation/epoch counter and only finalize the current generation
- Await cancel() fully before deciding whether to finalize
When it happens
Trigger: Calling finalize() on a video layer output while another code path has already invoked cancel() (or discard()) on it; the cancellation lands between output.finalize() and the next check.
Common situations: A user aborts a matting render in the UI mid-encode; a component unmounts and calls cancel() concurrently with finalize(); a timeout wrapper cancels the output while finalize is still awaiting.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Mediabunny did not return an output buffer.
- Mediabunny remux did not return an output buffer.
- No audio track found
- Live streams are not currently supported by Remotion. Sorry!
- Streams with UNIX timestamps are not currently supported by
AI-assisted analysis of remotion-dev/remotion@b2f4e34732 (2026-09-09).
Data as JSON: /api/errors/2d08005a40ac1dd9.
Report an issue: GitHub.