{"record":{"id":"31eb2e667b218450","repo":"can1357/oh-my-pi","slug":"codex-live-sideband-is-not-connected","errorCode":null,"errorMessage":"Codex live sideband is not connected","messagePattern":"Codex live sideband is not connected","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/live/transport.ts","lineNumber":377,"sourceCode":"\t}\n\n\t#reportFailure(message: string): void {\n\t\tif ((this.#state !== \"connecting\" && this.#state !== \"connected\") || this.#unexpectedFailureReported) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#unexpectedFailureReported = true;\n\t\ttry {\n\t\t\tthis.#options.callbacks.onEvent({ type: \"error\", message });\n\t\t} catch {}\n\t}\n\n\t/** Serialize one Frameless Bidi control message onto the call's sideband WebSocket. */\n\tsend(message: LiveClientMessage): Promise<void> {\n\t\tconst operation = this.#sendTail.then(() => {\n\t\t\tif (this.#state !== \"connected\") throw new Error(\"Live transport is not connected\");\n\t\t\tconst sideband = this.#sideband;\n\t\t\tif (!sideband || sideband.readyState !== WebSocket.OPEN) {\n\t\t\t\tthrow new Error(\"Codex live sideband is not connected\");\n\t\t\t}\n\t\t\tsideband.send(JSON.stringify(message));\n\t\t});\n\t\tthis.#sendTail = operation.catch(() => {});\n\t\treturn operation;\n\t}\n\n\t/** Queue 16 kHz mono Float32 PCM for native Opus transmission. */\n\tpushAudio(samples: Float32Array): void {\n\t\tif (this.#state !== \"connected\" || this.#muted || samples.length === 0) return;\n\t\tthis.#peer?.pushAudio(samples);\n\t}\n\n\t/** Enable or disable the native audio source and discard partial input when muted. */\n\tasync setMuted(muted: boolean): Promise<void> {\n\t\tthis.#muted = muted;\n\t\tif (this.#state === \"connected\") this.#peer?.setMuted(muted);\n\t}","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/live/transport.ts#L359-L395","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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."],"exampleFix":"// before\nawait transport.send(msg); // may throw 'sideband is not connected'\n// after\ntry {\n  await transport.send(msg);\n} catch (e) {\n  if (e.message.includes(\"sideband is not connected\")) {\n    outbox.push(msg);\n    await transport.reconnect();\n    await flushOutbox();\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"// no public readyState accessor? gate on your own socket observability\nlet sidebandOpen = false;\ntransport.onSidebandOpen(() => { sidebandOpen = true; flushOutbox(); });\ntransport.onSidebandClose(() => { sidebandOpen = false; });\nif (sidebandOpen) await transport.send(msg); else outbox.push(msg);","typeGuard":null,"tryCatchPattern":"try {\n  await transport.send(msg);\n} catch (e) {\n  if (e.message.includes(\"sideband is not connected\")) {\n    outbox.push(msg);\n    await transport.reconnect();\n  } else throw e;\n}","preventionTips":["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"],"tags":["websocket","race-condition","network","codex","live"],"backgroundTag":"websocket-closed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}