ruvnet/ruflo · error · Error

WASM agent not found: ${agentId}

Error message

WASM agent not found: ${agentId}

What it means

Thrown by promptWasmAgent(agentId, input) when agents.get(agentId) returns undefined — the agentId is not in the in-memory agent registry. The registry is a module-level Map keyed by IDs like 'wasm-agent-3-lkjx8', so an unknown ID means the agent was never created in this process, was already terminated, or the process restarted (the Map is not persisted).

Source

Thrown at v3/@claude-flow/cli/src/ruvector/agent-wasm.ts:195

}

/**
 * Send a prompt to a WASM agent.
 *
 * ADR-129 P1: JsModelProvider is now wired at creation time so the WASM
 * agent's internal conversation loop (multi-turn state, turn_count,
 * stop conditions) runs against a real LLM.  The echo-stub detection
 * block is kept as a fallback for keyless environments (CI, sandboxed
 * test runners) — behaviour is identical to the pre-P1 path when no
 * provider key is set.
 *
 * Billing note: every wasm_agent_prompt call with a provider key
 * configured makes a billable LLM call.  Use a keyless environment to
 * get the echo stub for cost-free sandboxing.
 */
export async function promptWasmAgent(agentId: string, input: string): Promise<string> {
  const entry = agents.get(agentId);
  if (!entry) throw new Error(`WASM agent not found: ${agentId}`);

  entry.info.state = 'running';
  try {
    const wasmResult = await entry.agent.prompt(input);
    entry.info.state = 'idle';
    syncAgentInfo(entry);

    // Detect the WASM echo stub (present when no JsModelProvider was
    // attached, i.e. keyless environments).
    const isEchoStub = typeof wasmResult === 'string' &&
      (wasmResult === `echo: ${input}` || /^echo: /.test(wasmResult.slice(0, 12)));

    if (!isEchoStub) {
      // JsModelProvider routed through the v3 provider system — return
      // the real response.  turn_count was already incremented by the
      // WASM runtime.
      return wasmResult;
    }

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Call listWasmAgents() before prompting to confirm the ID is still live in this process.
  2. If you need agent continuity across process restarts, use exportWasmState() to save and rehydrate — but note the underlying WasmAgent handle itself is not serializable; you must re-create.
  3. Treat the ID as ephemeral: create, use, and terminate within a single process lifetime.
  4. Check for a stray terminateWasmAgent call (including in error-handling paths) that removes the agent before the prompt.

Example fix

// before — assumes ID is still valid
const out = await promptWasmAgent(staleId, input);

// after — verify liveness, recreate if gone
const live = listWasmAgents().some(a => a.id === staleId);
if (!live) {
  const info = await createWasmAgent(config);
  return promptWasmAgent(info.id, input);
}
return promptWasmAgent(staleId, input);
Defensive patterns

Strategy: type-guard

Validate before calling

import { listWasmAgents, getWasmAgent } from './agent-wasm';

function assertAgentLive(agentId: string): void {
  if (!getWasmAgent(agentId)) {
    throw new Error(
      `agent ${agentId} not live. Active: ${listWasmAgents().map(a => a.id).join(', ') || '(none)'}`
    );
  }
}

assertAgentLive(agentId);
const out = await promptWasmAgent(agentId, input);

Type guard

function isLiveAgentId(id: string): boolean {
  return getWasmAgent(id) !== null;
}

Try / catch

try {
  return await promptWasmAgent(agentId, input);
} catch (e) {
  if (/WASM agent not found/.test(String(e))) {
    // Recreate and retry once — agent IDs are ephemeral.
    const info = await createWasmAgent(config);
    return promptWasmAgent(info.id, input);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling promptWasmAgent with an ID returned from a previous process run (after restart); passing an ID from listWasmAgents() after terminateWasmAgent was called on it; typo or copy-paste error in the agentId string; holding an ID across an await that outlived a terminate call elsewhere; using an ID from a different worker thread (the Map is per-process).

Common situations: Long-running server that creates an agent, restarts (deploy/restart), and a client retries with the old ID; CLI command creates an agent in one invocation and tries to prompt it in the next (separate processes); concurrent code path calls terminateWasmAgent while another caller still holds the ID; ID was persisted to disk via exportWasmState and reloaded, but the in-memory agent was not.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/a46f397d9c9ab3af. Report an issue: GitHub.