{"record":{"id":"00dc8d4ce1840eb7","repo":"openai/codex-plugin-cc","slug":"codex-app-server-broker-connection-is-not-connecte","errorCode":null,"errorMessage":"codex app-server broker connection is not connected.","messagePattern":"codex app-server broker connection is not connected\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugins/codex/scripts/lib/app-server.mjs","lineNumber":329,"sourceCode":"\n  async close() {\n    if (this.closed) {\n      await this.exitPromise;\n      return;\n    }\n\n    this.closed = true;\n    if (this.socket) {\n      this.socket.end();\n    }\n    await this.exitPromise;\n  }\n\n  sendMessage(message) {\n    const line = `${JSON.stringify(message)}\\n`;\n    const socket = this.socket;\n    if (!socket) {\n      throw new Error(\"codex app-server broker connection is not connected.\");\n    }\n    socket.write(line);\n  }\n}\n\nexport class CodexAppServerClient {\n  static async connect(cwd, options = {}) {\n    let brokerEndpoint = null;\n    if (!options.disableBroker) {\n      brokerEndpoint = options.brokerEndpoint ?? options.env?.[BROKER_ENDPOINT_ENV] ?? process.env[BROKER_ENDPOINT_ENV] ?? null;\n      if (!brokerEndpoint && options.reuseExistingBroker) {\n        brokerEndpoint = loadBrokerSession(cwd)?.endpoint ?? null;\n      }\n      if (!brokerEndpoint && !options.reuseExistingBroker) {\n        const brokerSession = await ensureBrokerSession(cwd, { env: options.env });\n        brokerEndpoint = brokerSession?.endpoint ?? null;\n      }\n    }","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/openai/codex-plugin-cc/blob/db52e28f4d9ded852ab3942cea316258ae4ef346/plugins/codex/scripts/lib/app-server.mjs#L311-L347","documentation":"BrokerCodexAppServerClient.sendMessage writes to this.socket. If the socket is null/undefined (sendMessage called before initialize() created it, or after close() where socket.end() was called and the reference cleared on a subsequent path), it throws. This guards the broker transport the same way the spawned client guards stdin.","triggerScenarios":"Calling request() before broker initialize() resolves (socket not yet created), or after close() ended the socket. Also if the broker connection errored and the socket was torn down.","commonSituations":"Lifecycle race with the broker: a notification or request issued during connection teardown, or retry logic that does not re-establish the broker session.","solutions":["Await CodexAppServerClient.connect() (which awaits initialize) before sending, so the socket exists.","After close(), create a new client rather than reusing; do not call request on a closed broker client.","If the socket errored, surface handleExit and reconnect via a fresh ensureBrokerSession/client.connect."],"exampleFix":"// before\nconst client = new BrokerCodexAppServerClient(cwd, { brokerEndpoint });\nclient.request('turn/start', params); // socket not yet connected\n// after\nconst client = await CodexAppServerClient.connect(cwd, { brokerEndpoint });\nawait client.request('turn/start', params);","handlingStrategy":"validation","validationCode":"if (!client.socket) throw new Error('broker socket unavailable; reconnect');","typeGuard":"/** @param {object} c @returns {boolean} */\nfunction hasBrokerSocket(c) { return Boolean(c.socket); }","tryCatchPattern":"try {\n  await client.request(method, params);\n} catch (e) {\n  if (/not connected/.test(e.message)) { /* re-establish broker session */ }\n  else throw e;\n}","preventionTips":["Use CodexAppServerClient.connect() so initialize() completes before any send.","Reconnect via ensureBrokerSession if the socket errors or closes."],"tags":["app-server","broker","transport","lifecycle"],"backgroundTag":null,"analyzedSha":"db52e28f4d9ded852ab3942cea316258ae4ef346","analyzedAt":"2026-08-13T05:13:20.855Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}