remotion-dev/remotion · error · Error
Video frame has not loaded
Error message
Video frame has not loaded
What it means
copyImageToClipboard draws the timeline thumbnail element into a canvas so it can be copied to the clipboard. For <video> elements it uses videoWidth/videoHeight as the canvas size; if the video has no decoded frame yet, both are 0 and drawing would fail, so the library throws this error upfront.
Solutions
- Wait for the video element's loadeddata/loadedmetadata (or seeked) event before copying.
- Check video.readyState >= 2 (HAVE_CURRENT_DATA) and videoWidth > 0 before invoking the copy action.
- Retry the copy after a short delay or after scrubbing the timeline to force frame decode.
- If the source is broken, fix the video URL/source so a frame can load.
Example fix
// before
await copyImageToClipboard(videoEl); // may throw
// after
if (videoEl.readyState < 2 || videoEl.videoWidth === 0) {
await new Promise((r) => videoEl.addEventListener('loadeddata', r, {once: true}));
}
await copyImageToClipboard(videoEl); Defensive patterns
Strategy: validation
Validate before calling
function canCopyVideoFrame(v) {
return v instanceof HTMLVideoElement && v.readyState >= 2 && v.videoWidth > 0 && v.videoHeight > 0;
} Type guard
const isVideoWithFrame = (el: Element): el is HTMLVideoElement => el instanceof HTMLVideoElement && el.videoWidth > 0 && el.videoHeight > 0;
Try / catch
try {
await copyImageToClipboard(el);
} catch (err) {
if (err.message === 'Video frame has not loaded') {
// retry after loadeddata or show a 'frame not ready' toast
}
} Prevention
- Check video.readyState >= 2 before copy actions
- Listen for loadeddata/seeked before enabling the copy menu item
- Handle broken sources by verifying the video loads at all
When it happens
Trigger: Right-clicking 'Copy image to clipboard' on a Timeline/Sequence thumbnail whose <video> element has not finished loading or decoding any frame (videoWidth === 0 || videoHeight === 0).
Common situations: Copying a video element immediately after page load or seek before metadata/first frame is ready; slow network so the video has not buffered; a broken or unsupported video source so the frame never loads.
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
- Could not create canvas context
- acceptableTimeShift has been removed. Use…
- Cannot decode " ": it is encoded with Apple ProRes, which…
- Cannot paste effects: no effects were copied
- cannot process avc stream
AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18).
Data as JSON: /api/errors/308c75d4953569e7.
Report an issue: GitHub.
Appendix: source
Thrown at packages/studio/src/components/Timeline/get-sequence-context-menu-items.ts:89
} else if (element.tagName === 'IMG') {
const image = element as HTMLImageElement;
if (image.naturalWidth === 0 || image.naturalHeight === 0) {
throw new Error('Image has not loaded');
}
canvas = document.createElement('canvas');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
const context = canvas.getContext('2d');
if (!context) {
throw new Error('Could not create canvas context');
}
context.drawImage(image, 0, 0);
} else if (element.tagName === 'VIDEO') {
const video = element as HTMLVideoElement;
if (video.videoWidth === 0 || video.videoHeight === 0) {
throw new Error('Video frame has not loaded');
}
canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const context = canvas.getContext('2d');
if (!context) {
throw new Error('Could not create canvas context');
}
context.drawImage(video, 0, 0);
} else {
throw new Error('Expected an image, video, or canvas element');
}
const blob = new Promise<Blob>((resolve, reject) => {
canvas.toBlob((result) => {
if (result) {View on GitHub (pinned to 46a3a6bf13)