Hmbown/CodeWhale · error · ExecError

unknown transport

Error message

unknown transport ${computer.transport}

What it means

executorFor() dispatches a computer binding to its transport implementation (local, ssh, docker, hdc) and throws this ExecError for any transport value outside the supported set. It is a fail-loud guard against misconfigured computer registrations, per the misconfiguration-fails-loud convention.

Solutions

  1. Fix computer.transport in the config to one of: ssh, docker, hdc (or a valid local setup)
  2. Check for case/typo mistakes — the value is matched exactly
  3. If migrating from an older config, update the transport name to the current set
  4. Add validation at config-load time to reject unknown transports early
  5. Log/inspect the actual computer object to see the offending value

Example fix

// before
{ "computer": { "transport": "ssh " } } // trailing space -> unknown transport
// after
{ "computer": { "transport": "ssh" } }
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = new Set(["ssh", "docker", "hdc"]);
if (!SUPPORTED.has(computer?.transport)) throw new Error(`transport must be one of ssh|docker|hdc, got ${computer?.transport}`);
const ex = executorFor(computer);

Type guard

function isKnownTransport(c) { return c && ["ssh", "docker", "hdc"].includes(c.transport); }

Try / catch

try {
  const ex = executorFor(computer);
} catch (e) {
  if (e.message.startsWith("unknown transport")) {
    console.error(`bad transport in binding: ${JSON.stringify(computer)}`); // fail loud, show config
    throw e;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling executorFor(computer) where computer.transport is anything other than "ssh"|"docker"|"hdc" (and not handled by the local path above): typos like "local", "docker2", null/undefined transport, or stale saved config from an older schema.

Common situations: Typo in a config file's transport field; config written by hand or by an older plugin version using a removed transport name; programmatically constructed binding with a wrong string; JSON config with casing differences ("SSH" vs "ssh").

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/8bc61392f5ced3b6. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/plugins/computer-use/src/transport.mjs:349

  if (computer.transport === "local") {
    // Test hook: exercise the out-of-process wire path (desktop app / ssh
    // agent) in-process, so wire argument preparation is covered by tests.
    if (process.env.CODEWHALE_CU_TEST_REMOTE === "1") {
      const { handle } = await import("./app-handler.mjs");
      return { ...appExec({ id: "test", name: "test app" }), remote: (request) => handle(request, { sessionId: SESSION_ID, signal: currentSignal() }) };
    }
    const status = await ensureApp();
    if (status.via === "app") {
      if (status.app.sessionProtocol !== 2) throw Object.assign(new ExecError("The installed Computer Use helper needs an update for isolated sessions and disconnect cleanup. Rebuild/reinstall it, then retry."), { code: "app_upgrade_required" });
      if (process.platform === "darwin" && status.app.backgroundProtocol !== 1) throw Object.assign(new ExecError("The installed Computer Use app predates background scrolling, scoped observations and foreground preemption. Update and restart the helper before using it."), { code: "app_upgrade_required" });
      return appExec(status.app);
    }
    return { ...localExec(), appReason: status.reason };
  }
  if (computer.transport === "ssh") return sshExec(computer, binding);
  if (computer.transport === "docker") return dockerExec(computer, binding);
  if (computer.transport === "hdc") return hdcExec(computer);
  throw new ExecError(`unknown transport ${computer.transport}`);
}

/**
 * Map a computer to its backend module. Local platform is fixed; ssh
 * computers may carry platformHint (probed at registration).
 */
function effectivePlatform(computer) {
  let platform = computer.platform ?? computer.platformHint;
  if (!platform) {
    if (computer.transport === "local") platform = process.platform;
    else if (computer.transport === "hdc") platform = "harmonyos";
    else if (computer.transport === "docker") platform = "linux"; // spawned containers are always the Linux desktop image
    else platform = "linux"; // conservative default for ssh; registration probes it
  }
  return platform;
}

/** Identity of the effective route, excluding catalog presentation metadata. */

View on GitHub (pinned to 73e0f67d83)