{"record":{"id":"a40b32957231662a","repo":"remotion-dev/remotion","slug":"htmlincanvas-components-cannot-be-nested-chrome","errorCode":null,"errorMessage":"<HtmlInCanvas> components cannot be nested. Chrome does not reliably render nested HTML-in-canvas subtrees. Consider merging the effects into one <HtmlInCanvas> if you can.","messagePattern":"<HtmlInCanvas> components cannot be nested\\. Chrome does not reliably render nested HTML-in-canvas subtrees\\. Consider merging the effects into one <HtmlInCanvas> if you can\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/HtmlInCanvas.tsx","lineNumber":402,"sourceCode":"\t\t{\n\t\t\twidth,\n\t\t\theight,\n\t\t\teffects,\n\t\t\tchildren,\n\t\t\tonPaint,\n\t\t\tonInit,\n\t\t\tpixelDensity,\n\t\t\tcontrols,\n\t\t\tstyle,\n\t\t},\n\t\tref,\n\t) => {\n\t\tconst isInsideAncestorHtmlInCanvas = useContext(\n\t\t\tHtmlInCanvasAncestorContext,\n\t\t);\n\t\tassertHtmlInCanvasDimensions(width, height);\n\t\tif (isInsideAncestorHtmlInCanvas) {\n\t\t\tthrow new Error(\n\t\t\t\t'<HtmlInCanvas> components cannot be nested. Chrome does not reliably render nested HTML-in-canvas subtrees. Consider merging the effects into one <HtmlInCanvas> if you can.',\n\t\t\t);\n\t\t}\n\n\t\tconst resolvedPixelDensity = resolveHtmlInCanvasPixelDensity(pixelDensity);\n\t\tconst canvasWidth = Math.ceil(width * resolvedPixelDensity);\n\t\tconst canvasHeight = Math.ceil(height * resolvedPixelDensity);\n\t\tconst {delayRender, continueRender, cancelRender} = useDelayRender();\n\t\tconst {isClientSideRendering, isRendering} = useRemotionEnvironment();\n\t\tconst canRetryMissingPaintRecord = !isRendering || isClientSideRendering;\n\t\tconst usesDirectLayoutCanvas =\n\t\t\tonPaint === undefined && onInit === undefined;\n\n\t\tif (!isHtmlInCanvasSupported()) {\n\t\t\tcancelRender(new Error(HTML_IN_CANVAS_UNSUPPORTED_MESSAGE));\n\t\t}\n\n\t\tconst canvas2dRef = useRef<HTMLCanvasElement | null>(null);","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/remotion-dev/remotion/blob/10db9de07356446fb0edb3c3ae211369b693d18b/packages/core/src/HtmlInCanvas.tsx#L384-L420","documentation":"Remotion's <HtmlInCanvas> rasterizes an HTML subtree into a <canvas> snapshot. Because Chrome cannot reliably draw an HTML-in-canvas subtree that itself contains another canvas painted from HTML, the component forbids nesting: an internal React context (HtmlInCanvasAncestorContext) is set by every <HtmlInCanvas>, and any descendant <HtmlInCanvas> sees it and throws synchronously during render. The error surfaces in Remotion Studio and at the start of a render.","triggerScenarios":"Rendering JSX where a <HtmlInCanvas> appears anywhere in the children tree of another <HtmlInCanvas> - directly or indirectly through a child component/composition that itself renders <HtmlInCanvas>. The check runs on mount of the inner component (HtmlInCanvasContent, packages/core/src/HtmlInCanvas.tsx:401).","commonSituations":"Wrapping a whole scene in <HtmlInCanvas> to apply an effect while a reusable child (e.g. a lower-third that already uses <HtmlInCanvas> for its own effect) is placed inside; composing shared libraries that each snapshot their HTML; refactoring an existing <HtmlInCanvas> composition into another one during effect work.","solutions":["Keep only the outermost <HtmlInCanvas> and merge the visual treatments into its single effects array (e.g. effects={[blur(5), outline({width: 3})]})","Move the inner <HtmlInCanvas> out of the parent's children so the two become siblings, not ancestor/descendant","If the outer <HtmlInCanvas> existed only to apply an effect, remove it and apply the effect directly to the inner <HtmlInCanvas> or a plain <Sequence>"],"exampleFix":"// before - inner component also renders <HtmlInCanvas>\n<HtmlInCanvas width={1920} height={1080} effects={[blur(5)]}>\n  <LowerThirdWithOwnHtmlInCanvas />\n</HtmlInCanvas>\n\n// after - one <HtmlInCanvas>, effects merged\n<HtmlInCanvas\n  width={1920}\n  height={1080}\n  effects={[blur(5), lowerThirdOutline]}\n>\n  <LowerThirdContent />\n</HtmlInCanvas>","handlingStrategy":"validation","validationCode":"// Dev-time check: ensure a candidate subtree does not itself contain <HtmlInCanvas>\nimport type {ReactNode} from 'react';\n\nconst subtreeContainsHtmlInCanvas = (node: ReactNode): boolean => {\n  if (Array.isArray(node)) return node.some(subtreeContainsHtmlInCanvas);\n  if (!node || typeof node !== 'object') return false;\n  const el = node as {\n    type?: {name?: string; displayName?: string};\n    props?: {children?: ReactNode};\n  };\n  const name = el.type?.displayName ?? el.type?.name;\n  if (name === 'HtmlInCanvas') return true;\n  return subtreeContainsHtmlInCanvas(el.props?.children);\n};\n\n// before rendering: if (subtreeContainsHtmlInCanvas(children)) -> do not wrap in <HtmlInCanvas>","typeGuard":null,"tryCatchPattern":"// Studio preview only: catch the render-time throw with an ErrorBoundary\n// (during `remotion render` this error is fatal by design)\nclass HtmlInCanvasBoundary extends React.Component<\n  {children: ReactNode; fallback: ReactNode},\n  {hasError: boolean}\n> {\n  state = {hasError: false};\n  static getDerivedStateFromError() {\n    return {hasError: true};\n  }\n  render() {\n    return this.state.hasError ? this.props.fallback : this.props.children;\n  }\n}","preventionTips":["Keep one <HtmlInCanvas> per subtree and merge visual treatments into its effects array instead of nesting snapshots","Audit reusable components for internal <HtmlInCanvas> usage before embedding them in an outer <HtmlInCanvas>","Treat <HtmlInCanvas> like an effect boundary, not a layout wrapper - apply effects to plain content"],"tags":["remotion","html-in-canvas","nesting","react-context","render-time-error"],"backgroundTag":"unsupported-component-nesting","analyzedSha":"10db9de07356446fb0edb3c3ae211369b693d18b","analyzedAt":"2026-08-22T21:45:17.748Z","contentChangedAt":"2026-08-22T21:45:17.748Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}