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

  1. 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.
  2. Verify securityLevel is only 'sandbox' when the host environment actually injects the iframe; otherwise use the default 'strict' level.
  3. If managing the iframe manually, set its src to a same-origin blank document (srcdoc or about:blank) so contentDocument is accessible.
  4. 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

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


AI-assisted analysis of mermaid-js/mermaid@d93e9c88c0 (2026-08-12). Data as JSON: /api/errors/68df7df4e0aad195. Report an issue: GitHub.