can1357/oh-my-pi · error
Live transport is not connected
Error message
Live transport is not connected
What it means
send() serializes a live client message onto the call's sideband WebSocket, but only when the transport state is "connected". If the transport has never connected, or was closed/failed, it refuses to enqueue the write and throws synchronously at the state check.
Source
Thrown at packages/coding-agent/src/live/transport.ts:374
#handlePeerFailure(message: string): void {
this.#reportFailure(message);
}
#reportFailure(message: string): void {
if ((this.#state !== "connecting" && this.#state !== "connected") || this.#unexpectedFailureReported) {
return;
}
this.#unexpectedFailureReported = true;
try {
this.#options.callbacks.onEvent({ type: "error", message });
} catch {}
}
/** Serialize one Frameless Bidi control message onto the call's sideband WebSocket. */
send(message: LiveClientMessage): Promise<void> {
const operation = this.#sendTail.then(() => {
if (this.#state !== "connected") throw new Error("Live transport is not connected");
const sideband = this.#sideband;
if (!sideband || sideband.readyState !== WebSocket.OPEN) {
throw new Error("Codex live sideband is not connected");
}
sideband.send(JSON.stringify(message));
});
this.#sendTail = operation.catch(() => {});
return operation;
}
/** Queue 16 kHz mono Float32 PCM for native Opus transmission. */
pushAudio(samples: Float32Array): void {
if (this.#state !== "connected" || this.#muted || samples.length === 0) return;
this.#peer?.pushAudio(samples);
}
/** Enable or disable the native audio source and discard partial input when muted. */
async setMuted(muted: boolean): Promise<void> {View on GitHub (pinned to 9690622007)
Solutions
- Check transport state (or a connected flag) before calling send.
- Await connect() completion before sending any messages.
- Reconnect the transport, then resend queued messages.
- Guard sends inside try/catch and requeue on "not connected" errors.
Example fix
// before
transport.send({ type: "input", text });
// after
if (transport.state === "connected") {
await transport.send({ type: "input", text });
} else {
pendingQueue.push({ type: "input", text });
} Defensive patterns
Strategy: try-catch
Validate before calling
function canSend(t: { state: string }): boolean {
return t.state === "connected";
}
// gate sends:
if (canSend(transport)) await transport.send(msg); else outbox.push(msg); Type guard
const isConnected = (t: { state: string }): t is { state: "connected" } => t.state === "connected"; Try / catch
try {
await transport.send(msg);
} catch (e) {
if (e.message === "Live transport is not connected") {
outbox.push(msg);
await reconnectTransport();
} else throw e;
} Prevention
- Always await connect() before sending
- Track transport close events and pause producers
- Queue outbound messages during reconnection windows
- Avoid holding stale transport references across session restarts
When it happens
Trigger: Calling transport.send() before connect() resolves, after close(), or after the underlying call dropped and state transitioned away from "connected" (e.g. during reconnect).
Common situations: Sending a control message from an event handler racing a disconnect, forgetting to await connect(), or app code holding a stale transport reference after the live session ended.
Related errors
- Codex live sideband is not connected
- Daemon broker client is closed
- MCP server not connected: ${name}
- Transport not connected
- Vibe mode has exited; enter Vibe mode again before spawning
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/df8e98f586e623d7.
Report an issue: GitHub.