different-ai/openwork · error
MCP_APP_SANDBOX_RESOURCE_INVALID
MCP_APP_SANDBOX_RESOURCE_INVALID
Error message
The sandbox received an invalid HTML resource payload.
What it means
When the sandbox receives the ui/notifications/sandbox-resource-ready message from the host, the params.html field must be a string to be assigned to inner.srcdoc. If html is missing or not a string, the sandbox reports diagnostic MCP_APP_SANDBOX_RESOURCE_INVALID and ignores the message, so the iframe stays blank.
Source
Thrown at apps/server/src/mcp-app-sandbox.ts:109
readyState = inner.contentDocument?.readyState || null;
hasHtmlRoot = Boolean(inner.contentDocument?.documentElement);
scriptCount = inner.contentDocument?.scripts.length ?? null;
} catch {}
notifyHost("ui/notifications/sandbox-resource-loaded", { readyState, hasHtmlRoot, scriptCount });
});
inner.addEventListener("error", () => {
if (resourceAssigned) notifyHost("ui/notifications/sandbox-diagnostic", { code: "MCP_APP_SANDBOX_DOCUMENT_ERROR", message: "The sandbox iframe reported a document load error." });
});
document.body.appendChild(inner);
window.addEventListener("message", (event) => {
if (event.source === window.parent) {
if (event.origin !== hostOrigin) return;
if (event.data?.method === "ui/notifications/sandbox-resource-ready") {
const html = event.data?.params?.html;
const sandbox = event.data?.params?.sandbox;
if (typeof sandbox === "string" && /^(?:allow-scripts|allow-same-origin|\s)+$/.test(sandbox)) inner.setAttribute("sandbox", sandbox);
if (typeof html !== "string") {
notifyHost("ui/notifications/sandbox-diagnostic", { code: "MCP_APP_SANDBOX_RESOURCE_INVALID", message: "The sandbox received an invalid HTML resource payload." });
return;
}
try {
resourceAssigned = true;
inner.srcdoc = html;
notifyHost("ui/notifications/sandbox-resource-accepted");
} catch {
notifyHost("ui/notifications/sandbox-diagnostic", { code: "MCP_APP_SANDBOX_RESOURCE_ASSIGNMENT_FAILED", message: "The sandbox could not assign the HTML resource to its isolated document." });
}
return;
}
inner.contentWindow?.postMessage(event.data, "*");
return;
}
if (event.source === inner.contentWindow && event.origin === ownOrigin) {
window.parent.postMessage(event.data, hostTargetOrigin);
}
});View on GitHub (pinned to 2b7df46e8a)
Solutions
- Log event.data.params on the host side before posting and confirm html is a non-empty string.
- Fix the host sender so the fetched resource string is passed as params.html (stringify/decode if needed).
- Align host and sandbox versions so the message protocol (field names) matches.
- Add a host-side guard: only post sandbox-resource-ready when typeof html === 'string'.
Example fix
// before
notify({ method: "ui/notifications/sandbox-resource-ready", params: { html: await resource.text() ?? undefined } });
// after
const html = await resource.text();
if (typeof html === "string") notify({ method: "ui/notifications/sandbox-resource-ready", params: { html } }); Defensive patterns
Strategy: type-guard
Type guard
function isValidResource(m: unknown): m is { method: "ui/notifications/sandbox-resource-ready"; params: { html: string; sandbox?: string } } {
const d = m as any;
return d?.method === "ui/notifications/sandbox-resource-ready" && typeof d?.params?.html === "string";
} Try / catch
window.addEventListener("message", (e) => {
if (e.data?.code === "MCP_APP_SANDBOX_RESOURCE_INVALID") {
// re-request the resource from the host or surface a host-side error
}
}); Prevention
- Type the host→sandbox message protocol in shared code so params.html is always string
- Validate the resource string on the host before posting sandbox-resource-ready
- Version the host/sandbox message contract
When it happens
Trigger: Host posts { method: "ui/notifications/sandbox-resource-ready", params: {} } with no html, or with html as a Buffer/object/undefined — e.g. the host serialization step failed or the message was constructed with a different params shape.
Common situations: Host and sandbox protocol version mismatch (one side renamed html field); binary/encoded HTML passed instead of a string; host forwarding a resource payload where fetch failed and undefined leaked through.
Related errors
- MCP_APP_SANDBOX_DOCUMENT_ERROR
- MCP_APP_SANDBOX_RESOURCE_ASSIGNMENT_FAILED
- invalid_resource_uri
- invalid_resource_csp
- unsupported_resource_permissions
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/1f0aaf0737a18254.
Report an issue: GitHub.