{"record":{"id":"15d37d8928a1e097","repo":"remotion-dev/remotion","slug":"expected-an-image-video-or-canvas-element","errorCode":null,"errorMessage":"Expected an image, video, or canvas element","messagePattern":"Expected an image, video, or canvas element","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/studio/src/components/Timeline/get-sequence-context-menu-items.ts","lineNumber":102,"sourceCode":"\n\t\tcontext.drawImage(image, 0, 0);\n\t} else if (element.tagName === 'VIDEO') {\n\t\tconst video = element as HTMLVideoElement;\n\t\tif (video.videoWidth === 0 || video.videoHeight === 0) {\n\t\t\tthrow new Error('Video frame has not loaded');\n\t\t}\n\n\t\tcanvas = document.createElement('canvas');\n\t\tcanvas.width = video.videoWidth;\n\t\tcanvas.height = video.videoHeight;\n\t\tconst context = canvas.getContext('2d');\n\t\tif (!context) {\n\t\t\tthrow new Error('Could not create canvas context');\n\t\t}\n\n\t\tcontext.drawImage(video, 0, 0);\n\t} else {\n\t\tthrow new Error('Expected an image, video, or canvas element');\n\t}\n\n\tconst blob = new Promise<Blob>((resolve, reject) => {\n\t\tcanvas.toBlob((result) => {\n\t\t\tif (result) {\n\t\t\t\tresolve(result);\n\t\t\t} else {\n\t\t\t\treject(new Error('Could not convert image to PNG'));\n\t\t\t}\n\t\t}, 'image/png');\n\t});\n\n\tawait navigator.clipboard.write([\n\t\tnew ClipboardItem({\n\t\t\t'image/png': blob,\n\t\t}),\n\t]);\n};","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/remotion-dev/remotion/blob/46a3a6bf13ca367376ff18bbb06dae2e87e0d068/packages/studio/src/components/Timeline/get-sequence-context-menu-items.ts#L84-L120","documentation":"Thrown in copyImageToClipboard (a generic guard at the end of the element-dispatch chain): the function expects the timeline item thumbnail source to be an HTMLImageElement, HTMLCanvasElement, or HTMLVideoElement, but received an element with some other tagName. It fires when the caller passes an unsupported DOM element type to the clipboard-copy routine — the image and VIDEO branches have already been exhausted. This is an internal invariant violation rather than user input error; the caller should only pass elements produced from a sequence thumbnail that are one of the three supported media types.","triggerScenarios":"Invoking the copy-image action on a timeline thumbnail element that is not an <img>, <video>, or <canvas> — e.g. a <div>, <svg>, or other wrapper element was passed instead of the media node.","commonSituations":"DOM structure changes in Studio so the element resolved from the thumbnail no longer is a media element; custom code reusing copyImageToClipboard with an unsupported node.","solutions":["Pass the actual <img>, <video>, or <canvas> node, not a wrapper element.","Check element.tagName before calling and route unsupported types to a different handler.","For arbitrary elements, first draw them into a canvas (e.g. via foreignObject/SVG serialization) and copy that canvas.","Update Remotion Studio if a recent DOM refactor broke the element resolution."],"exampleFix":"// before\nawait copyImageToClipboard(wrapperDiv); // throws\n// after\nconst media = wrapperDiv.querySelector('img, video, canvas');\nif (media) await copyImageToClipboard(media);","handlingStrategy":"type-guard","validationCode":"if (!['IMG','VIDEO','CANVAS'].includes(el.tagName)) throw new TypeError('copyImageToClipboard requires img/video/canvas');","typeGuard":"const isCopyable = (el: Element): el is HTMLImageElement | HTMLVideoElement | HTMLCanvasElement =>\n  el instanceof HTMLImageElement || el instanceof HTMLVideoElement || el instanceof HTMLCanvasElement;","tryCatchPattern":"try {\n  await copyImageToClipboard(el);\n} catch (err) {\n  if (err.message.startsWith('Expected an image, video, or canvas')) {\n    // resolve the actual media node before retrying\n  }\n}","preventionTips":["Always pass the media node, not wrapper elements","Narrow with instanceof HTMLImageElement/HTMLVideoElement/HTMLCanvasElement first","Assert tagName in dev builds to catch DOM structure regressions early"],"tags":["type-mismatch","clipboard","dom"],"backgroundTag":"type-mismatch","analyzedSha":"46a3a6bf13ca367376ff18bbb06dae2e87e0d068","analyzedAt":"2026-09-18T00:12:20.256Z","contentChangedAt":"2026-09-18T00:12:20.256Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}