ruvnet/ruflo · error · Error
MCP init failed
Error message
MCP init failed
What it means
Fallback message thrown in the worker's ensureLoaded() when the WASM MCP server's initialize handle_message returned a JSON-RPC error whose .message is itself missing/falsy (initRes.error.message ?? "MCP init failed"). It indicates the initialize handshake failed inside the worker and the server did not provide a human-readable reason.
Source
Thrown at ruflo/src/ruvocal/src/lib/wasm/wasm.worker.ts:266
loadPromise = (async () => {
// TODO: load real rvagent_wasm.js via dynamic import once the static
// bundle exposes a worker-friendly init. Mock is functionally complete
// for the chat-ui's MCP integration test surface.
mcpServer = createMockServer();
gallery = createMockGallery();
const initReq = JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "initialize",
params: {
protocolVersion: "2024-11-05",
clientInfo: { name: "ruvocal-ui-worker", version: "1.0.0" },
},
});
const initRes = JSON.parse(mcpServer.handle_message(initReq));
if (initRes.error) throw new Error(initRes.error.message ?? "MCP init failed");
})();
await loadPromise;
}
ctx.addEventListener("message", async (event: MessageEvent<WorkerRequest>) => {
const { id, method, params } = event.data;
try {
await ensureLoaded();
if (!mcpServer || !gallery) throw new Error("WASM not initialized");
switch (method) {
case "load":
reply(id, true);
return;
case "callMcp": {View on GitHub (pinned to 6b01dc5a68)
Solutions
- Log the full initRes object (code + data) before the throw to recover the real reason.
- Confirm protocolVersion "2024-11-05" and clientInfo { name, version } match the server's expectations.
- Rebuild the worker glue and WASM binary together so handle_message's error contract is consistent.
- If the underlying cause is transient (worker cold-start under load), retry ensureLoaded once before surfacing the error.
Example fix
// before
const initRes = JSON.parse(mcpServer.handle_message(initReq));
if (initRes.error) throw new Error(initRes.error.message ?? "MCP init failed");
// after
const initRes = JSON.parse(mcpServer.handle_message(initReq));
if (initRes.error) {
throw new Error(`MCP init failed: ${initRes.error.message ?? `code=${initRes.error.code} data=${JSON.stringify(initRes.error.data)}`}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
const PROTOCOL = "2024-11-05";
function validInitParams(p: unknown): boolean {
return (
!!p &&
typeof (p as { protocolVersion?: string }).protocolVersion === "string" &&
typeof (p as { clientInfo?: { name?: string; version?: string } }).clientInfo?.name === "string" &&
typeof (p as { clientInfo?: { name?: string; version?: string } }).clientInfo?.version === "string"
);
}
if (!validInitParams({ protocolVersion: PROTOCOL, clientInfo: { name: "ruvocal-ui-worker", version: "1.0.0" } })) {
throw new Error("invalid initialize params");
} Type guard
function hasRpcError(r: unknown): r is { error: { code?: number; message?: string; data?: unknown } } {
return typeof r === "object" && r !== null && "error" in (r as object) && typeof (r as { error: unknown }).error === "object";
} Try / catch
try {
await ensureLoaded();
} catch (e) {
const msg = String((e as Error)?.message ?? e);
if (msg === "MCP init failed" || msg.startsWith("MCP init failed")) {
// re-load the worker module once, then surface a richer error with initRes.error.code
await reloadWorker();
await ensureLoaded();
} else throw e;
} Prevention
- Log the full initRes.error (code + data) before throwing so opaque failures become diagnosable.
- Rebuild worker glue and WASM binary from the same commit so the error contract is stable.
- Retry ensureLoaded once after a worker reload before surfacing failure to the user.
When it happens
Trigger: Worker constructs the (mock) MCP server, sends the initialize JSON-RPC frame, and the parsed response has an error object with no message field — e.g. { error: { code: -32603 } } — so the nullish-coalescing falls through to the generic string.
Common situations: Worker WASM/glue version skew; the mock mcpServer.handle_message throws internally and the wrapper produces a code-only error; protocolVersion or clientInfo shape rejected without a descriptive message; worker memory/resource limits causing an opaque failure.
Related errors
- MCP initialization failed: ${initResponse.error.message}
- Failed to load WASM module
- Template not found: ${id}
- Failed to initialize @ruvector/rvagent-wasm: ${err}
- Failed to initialize @ruvector/ruvllm-wasm: ${err}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/137a52bea9f33c17.
Report an issue: GitHub.