can1357/oh-my-pi · error · ToolError
cmux socket is not connected
Error message
cmux socket is not connected
What it means
#sendLine refuses to write to a cmux socket that is null or destroyed, throwing this ToolError synchronously. The client treats a destroyed socket as unrecoverable per-call state: the connection must be re-established (via connect/request) before lines can be sent. It surfaces when a request races a socket teardown (error, close, close(), or a timeout-triggered desync destroy).
Source
Thrown at packages/coding-agent/src/tools/browser/cmux/socket-client.ts:326
} catch (err) {
job.reject(err instanceof Error ? err : new ToolError(String(err)));
} finally {
if (this.#activeJob === job) {
this.#activeJob = null;
}
}
}
} finally {
this.#pumping = false;
if (this.#queue.length > 0 && !this.#disposed) {
this.#pump();
}
}
}
#sendLine(line: string, timeoutMs: number): Promise<string> {
if (!this.#socket || this.#socket.destroyed) {
throw new ToolError("cmux socket is not connected");
}
const read = this.#nextLine(timeoutMs);
this.#socket.write(`${line}\n`, err => {
if (err) {
this.#handleSocketFailure(err);
}
});
return read;
}
#nextLine(timeoutMs: number): Promise<string> {
const { promise, resolve, reject } = Promise.withResolvers<string>();
let waiter: LineWaiter;
const timer = setTimeout(() => {
const index = this.#lineWaiters.indexOf(waiter);
if (index >= 0) {
this.#lineWaiters.splice(index, 1);
}View on GitHub (pinned to 9690622007)
Solutions
- Create a new CmuxSocketClient (or await connect() again) — the class resets #socket to null on failure and never auto-reconnects an existing instance from sendLine
- Don't reuse a client after close(); construct a fresh instance per lifecycle
- Reduce cross-task sharing so one request's timeout/desync destroy doesn't poison concurrent requests; serialize requests or give each task its own client
- Check for prior 'cmux socket error'/'cmux socket closed' logs explaining why the socket was destroyed
Example fix
// before
await client.request("tabs.list", {}); // socket died earlier
// after
if (!client) client = new CmuxSocketClient({ socketPath });
try {
await client.connect();
await client.request("tabs.list", {});
} catch {
client.close();
client = new CmuxSocketClient({ socketPath });
} Defensive patterns
Strategy: retry
Type guard
function isSocketUsable(c: CmuxSocketClient): boolean {
// no public accessor exists; rely on connect() instead
return true;
} Try / catch
try {
result = await client.request(method, params);
} catch (err) {
if (err instanceof ToolError && err.message === "cmux socket is not connected") {
client.close();
client = new CmuxSocketClient({ socketPath });
await client.connect();
result = await client.request(method, params);
} else throw err;
} Prevention
- Never call request() on a client after close(); create a new instance
- Reconnect (await client.connect()) after any socket error/timeout before the next request
- Avoid sharing one client across tasks that can time out independently; a desync destroy tears the socket down for everyone
- Wrap request sequences in a helper that recreates the client on connection-state errors
When it happens
Trigger: Calling request()/sendLine after close() disposed the client; the underlying net.Socket errored or closed while a job was being pumped; a prior request timed out and #destroySocketForDesync() nulled the socket; a concurrent request triggered #handleSocketFailure.
Common situations: Long-lived client kept after a network blip; requesting before awaiting connect() on a failed connection; sharing one CmuxSocketClient across async tasks where one task's timeout tears the socket down for others; using the client after close().
Related errors
- native spelling thread stopped
- Agent is already processing. Use steer() or followUp() to qu
- Failed to open auth database at '${dbPath}' after ${maxAttem
- OAuth refresh ownership was lost before persistence
- No credential with id=${id}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/acf2bf417f92dec7.
Report an issue: GitHub.