different-ai/openwork · error · Error
${config.name} root element is missing.
Error message
${config.name} root element is missing. What it means
mountMcpApp renders the MCP App's React tree into the DOM element with id "root". If that element is absent when mounting, it throws with the app config's name, because createRoot requires a real container element. This is a host-page integration error, not a React error.
Source
Thrown at packages/mcp-apps/src/shared/bridge.tsx:52
}
createdApp.ontoolcancelled = ({ reason }) => {
setResultError(reason ?? "The tool call was cancelled.")
}
},
})
useHostStyles(app, app?.getHostContext())
if (error || resultError) {
return <StatusCard>{error?.message ?? resultError}</StatusCard>
}
if (!payload) {
return <StatusCard>{config.waitingLabel}</StatusCard>
}
return <>{config.render(payload, app)}</>
}
const root = document.getElementById("root")
if (!root) throw new Error(`${config.name} root element is missing.`)
createRoot(root).render(
<StrictMode>
<AppRoot />
</StrictMode>,
)
}
View on GitHub (pinned to 2b7df46e8a)
Solutions
- Ensure the host HTML contains <div id="root"></div> before the app script executes.
- Defer mounting until the DOM is ready: wrap mountMcpApp in DOMContentLoaded or place the script tag at the end of <body> with type=module/defer.
- If the host uses a different container id, add/adjust the root lookup in the mount config or template.
- If mounting into shadow DOM, mount on the shadow root's element rather than relying on document.getElementById.
Example fix
// before <script type="module" src="/src/main.tsx"></script> // after <div id="root"></div> <script type="module" src="/src/main.tsx"></script>
Defensive patterns
Strategy: validation
Validate before calling
if (!document.getElementById("root")) throw new Error("Host page must include <div id=\"root\"></div>");
mountMcpApp({ config }); Type guard
function hasRoot(doc: Document): boolean {
return doc.getElementById("root") !== null;
} Try / catch
try {
mountMcpApp({ config });
} catch (e) {
if (e.message.endsWith("root element is missing.")) renderFallbackInto(document.body);
else throw e;
} Prevention
- Always ship <div id="root"></div> in the host HTML template
- Mount after DOMContentLoaded or use defer/module scripts
- Agree on one container id convention between host pages and MCP apps
When it happens
Trigger: Calling mountMcpApp({ config }) in a document whose HTML lacks <div id="root">, mounting before DOMContentLoaded (script runs in <head>), or mounting into a shadow root/DOM where the root node has a different id.
Common situations: Vite/webpack dev server serving the built bundle before index.html's root div exists; host page embedding the MCP app inside a custom container with a different id; React 18+ createRoot stricter than legacy ReactDOM.render which auto-created containers.
Related errors
- MCP_APP_SANDBOX_RESOURCE_ASSIGNMENT_FAILED
- invalid_resource_uri
- invalid_resource_csp
- unsupported_resource_permissions
- unsupported_transport
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/4f1f59aa65fcdb52.
Report an issue: GitHub.