can1357/oh-my-pi · error · ToolError

formatCmuxError(response.error)

Error message

formatCmuxError(response.error)

What it means

When the response envelope has ok === false, the request itself failed on the cmux server side; #parseResponse throws a ToolError whose message is formatCmuxError(response.error) — i.e. '<code>: <message>[ details=<json>]'. This is the daemon's structured application-level error, faithfully surfaced to the caller.

Source

Thrown at packages/coding-agent/src/tools/browser/cmux/socket-client.ts:401

	#parseResponse(line: string): Record<string, unknown> {
		if (line.startsWith("ERROR:")) {
			throw new ToolError(line);
		}
		let payload: unknown;
		try {
			payload = JSON.parse(line);
		} catch (err) {
			throw new ToolError(`Invalid cmux socket JSON response: ${err instanceof Error ? err.message : String(err)}`);
		}
		if (!payload || typeof payload !== "object") {
			throw new ToolError("Invalid cmux socket response: expected object");
		}
		const response = payload as { ok?: unknown; result?: unknown; error?: CmuxErrorPayload };
		if (response.ok === true) {
			return (response.result ?? {}) as Record<string, unknown>;
		}
		if (response.ok === false) {
			throw new ToolError(formatCmuxError(response.error));
		}
		throw new ToolError("Invalid cmux socket response: missing ok flag");
	}

	#handleSocketFailure(err: Error): void {
		if (this.#disposed) return;
		this.#connected = false;
		this.#connectPromise = null;
		this.#rejectAll(new ToolError(`cmux socket error: ${err.message}`));
		this.#socket?.destroy();
		this.#socket = null;
	}

	#handleSocketClose(): void {
		const hadPendingRead = this.#lineWaiters.length > 0;
		this.#connected = false;
		this.#connectPromise = null;
		this.#socket = null;

View on GitHub (pinned to 9690622007)

Solutions

  1. Parse the code/message in the thrown text and fix the request accordingly (bad id, bad URL, bad params)
  2. Check whether the referenced resource (tab, session) still exists and re-list before acting
  3. Inspect daemon logs for the matching error code if the message is opaque
  4. Retry transient codes (timeouts, busy) with backoff
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return await client.request(method, params);
} catch (err) {
  if (err instanceof ToolError) {
    const m = /^(\w[\w.-]*):\s(.+?)(?: details=(.*))?$/s.exec(err.message);
    if (m) {
      const [, code, message, details] = m;
      // branch on code: retry transient codes, re-list resources for not-found, surface the rest
    }
  }
  throw err;
}

Prevention

When it happens

Trigger: Any cmux request the daemon completes with ok:false: invalid params, target/tab not found, navigation failure, permission denied, internal daemon error. The thrown message equals the server's error code/message/details.

Common situations: Requesting a tab id that no longer exists; navigating to an unreachable URL; daemon-side validation rejecting params; relay authorized but command not permitted.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/2e0914a35f04a366. Report an issue: GitHub.