can1357/oh-my-pi · error
Codex live sideband is not connected
Error message
Codex live sideband is not connected
What it means
send() also verifies that the underlying sideband WebSocket exists and is in the OPEN readyState at write time. Even when transport state says "connected", the socket may have been closed or is CONNECTING/CLOSING; writing then would silently drop bytes, so it throws instead.
Source
Thrown at packages/coding-agent/src/live/transport.ts:377
}
#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> {
this.#muted = muted;
if (this.#state === "connected") this.#peer?.setMuted(muted);
}View on GitHub (pinned to 9690622007)
Solutions
- Retry after the transport reconnects the sideband.
- Buffer messages and flush once the sideband reports OPEN.
- Subscribe to transport close/error events to pause sends proactively.
- Check WS readyState gating in your send wrapper.
Example fix
// before
await transport.send(msg); // may throw 'sideband is not connected'
// after
try {
await transport.send(msg);
} catch (e) {
if (e.message.includes("sideband is not connected")) {
outbox.push(msg);
await transport.reconnect();
await flushOutbox();
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// no public readyState accessor? gate on your own socket observability
let sidebandOpen = false;
transport.onSidebandOpen(() => { sidebandOpen = true; flushOutbox(); });
transport.onSidebandClose(() => { sidebandOpen = false; });
if (sidebandOpen) await transport.send(msg); else outbox.push(msg); Try / catch
try {
await transport.send(msg);
} catch (e) {
if (e.message.includes("sideband is not connected")) {
outbox.push(msg);
await transport.reconnect();
} else throw e;
} Prevention
- Serialize sends behind a small outbox that flushes on OPEN
- Listen for sideband close/error events and pause producers
- Add jittered retries for transient WS drops
- Keep sessions alive with expected keepalive/heartbeat traffic
When it happens
Trigger: State says "connected" but the sideband WebSocket just closed, is still handshaking (CONNECTING), or was never attached — a race between a close event and an in-flight send().
Common situations: Network blip closing the WS mid-session, sending immediately after connect before the sideband finished opening, server-side timeout closing the sideband while the main call lives on.
Related errors
- Live transport is not connected
- Codex live signaling failed (${response.status}): ${detail}
- Codex live signaling returned an empty SDP answer
- Codex live signaling returned no valid call ID
- Codex request failed (${code}): ${message || "Request failed
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/31eb2e667b218450.
Report an issue: GitHub.