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

  1. Log event.data.params on the host side before posting and confirm html is a non-empty string.
  2. Fix the host sender so the fetched resource string is passed as params.html (stringify/decode if needed).
  3. Align host and sandbox versions so the message protocol (field names) matches.
  4. 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

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


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/1f0aaf0737a18254. Report an issue: GitHub.