mermaid-js/mermaid · error · Error
Sandbox iframe #i${id} is missing its content document
Error message
Sandbox iframe #i${id} is missing its content document What it means
Thrown by getDiagramRoot when securityLevel is 'sandbox' but the iframe element `#i<id>` either doesn't exist in the document or its contentDocument is null/undefined. In sandbox mode the diagram renders inside an iframe; getDiagramRoot selects `#i<id>` and reads .node().contentDocument to obtain the inner document. A missing iframe or a same-origin/cross-origin contentDocument that isn't accessible yields undefined.
Source
Thrown at packages/mermaid/src/utils/diagramRoot.ts:22
export interface DiagramRoot {
/** Selection of the body that diagram elements should be queried from. */
root: D3HtmlSelection<HTMLElement>;
/** Owner document of {@link root} (the iframe document in sandbox mode). */
doc: Document;
}
/**
* Resolves the root selection a renderer should draw into, accounting for
* `securityLevel: 'sandbox'` where the diagram lives inside an `#i<id>`
* iframe. Centralizes the sandbox handling that was previously copy-pasted
* (with non-null assertions) into every renderer.
*/
export const getDiagramRoot = (id: string, securityLevel?: string): DiagramRoot => {
if (securityLevel === 'sandbox') {
const sandboxElement = select<HTMLIFrameElement, unknown>('#i' + id);
const doc = sandboxElement.node()?.contentDocument;
if (!doc) {
throw new Error(`Sandbox iframe #i${id} is missing its content document`);
}
return { root: select(doc.body) as unknown as D3HtmlSelection<HTMLElement>, doc };
}
return { root: select('body') as unknown as D3HtmlSelection<HTMLElement>, doc: document };
};
View on GitHub (pinned to d93e9c88c0)
Solutions
- Ensure the sandbox iframe with id `i${diagramId}` exists and is same-origin/loaded before rendering — let mermaid's own sandbox setup create it rather than calling getDiagramRoot standalone.
- Verify securityLevel is only 'sandbox' when the host environment actually injects the iframe; otherwise use the default 'strict' level.
- If managing the iframe manually, set its src to a same-origin blank document (srcdoc or about:blank) so contentDocument is accessible.
- Await the iframe's load event before invoking the renderer.
Example fix
// before — calling renderer before iframe ready / wrong id
getDiagramRoot('myDiagram', 'sandbox'); // #imyDiagram missing → throws
// after
const iframe = document.getElementById('i' + diagramId) as HTMLIFrameElement;
await new Promise((res) => iframe.addEventListener('load', res, { once: true }));
getDiagramRoot(diagramId, 'sandbox'); Defensive patterns
Strategy: validation
Validate before calling
function getSandboxDoc(id: string): Document | null {
const iframe = document.getElementById('i' + id) as HTMLIFrameElement | null;
return iframe?.contentDocument ?? null;
}
if (securityLevel === 'sandbox' && !getSandboxDoc(id)) throw new Error(`sandbox iframe #i${id} not ready`); Type guard
function isIframeReady(id: string): boolean {
const f = document.getElementById('i' + id) as HTMLIFrameElement | null;
return !!f && !!f.contentDocument;
} Try / catch
try { return getDiagramRoot(id, securityLevel); } catch (e) { if (/missing its content document/.test(String(e))) { await waitForIframe(id); return getDiagramRoot(id, securityLevel); } throw e; } Prevention
- Let mermaid create the sandbox iframe; don't call getDiagramRoot standalone.
- Await the iframe load event before rendering.
- Keep the iframe same-origin (srcdoc/about:blank) so contentDocument is readable.
When it happens
Trigger: Calling getDiagramRoot(id, 'sandbox') before the sandbox iframe `#i<id>` has been injected into the DOM, when the iframe id doesn't match the diagram id, or when the iframe's contentDocument is null (cross-origin src, or not yet loaded). select returns an empty selection → .node() is null → optional chain yields undefined.
Common situations: Race condition: renderer runs before the iframe is created/loaded; a securityLevel mismatch (config says sandbox but the host page didn't create the iframe); cross-origin iframe src blocking contentDocument access; or an id mismatch between the mermaid diagram id and the iframe element id.
Related errors
- Nodes and querySelector are both undefined
- Unknown layout algorithm: ${data4Layout.layoutAlgorithm}
- Both layout algorithms ${algorithm} and ${fallback} are not
- No such shape: ${node.shape}. Please check your syntax.
- The given radii are too small to create an arc between the p
AI-assisted analysis of mermaid-js/mermaid@d93e9c88c0 (2026-08-12).
Data as JSON: /api/errors/68df7df4e0aad195.
Report an issue: GitHub.