openai/codex-plugin-cc · error · Error

codex app-server stdin is not available.

Error message

codex app-server stdin is not available.

What it means

SpawnedCodexAppServerClient.sendMessage writes a JSONL line to this.proc.stdin. If proc is null or proc.stdin is null/destroyed (process not spawned, already exited, or stdin closed during shutdown), it throws. This is the direct-transport variant; the broker variant has its own socket check.

Source

Thrown at plugins/codex/scripts/lib/app-server.mjs:272

            } catch {
              // Best-effort cleanup inside an unref'd timer — swallow errors
              // to avoid crashing the host process during shutdown.
            }
          } else {
            this.proc.kill("SIGTERM");
          }
        }
      }, 50).unref?.();
    }

    await this.exitPromise;
  }

  sendMessage(message) {
    const line = `${JSON.stringify(message)}\n`;
    const stdin = this.proc?.stdin;
    if (!stdin) {
      throw new Error("codex app-server stdin is not available.");
    }
    stdin.write(line);
  }
}

class BrokerCodexAppServerClient extends AppServerClientBase {
  constructor(cwd, options = {}) {
    super(cwd, options);
    this.transport = "broker";
    this.endpoint = options.brokerEndpoint;
  }

  async initialize() {
    await new Promise((resolve, reject) => {
      const target = parseBrokerEndpoint(this.endpoint);
      this.socket = net.createConnection({ path: target.path });
      this.socket.setEncoding("utf8");
      this.socket.on("connect", resolve);

View on GitHub (pinned to db52e28f4d)

Solutions

  1. Always await client.initialize() (or use CodexAppServerClient.connect which calls it) before any request.
  2. Do not issue requests after close() or after observing process exit; check the closed/exit state.
  3. Handle process exit errors (handleExit rejects pending requests) and recreate the client if needed.

Example fix

// before
client.request('turn/start', params); // before initialize / after exit
// after
await client.initialize();
await client.request('turn/start', params);
Defensive patterns

Strategy: validation

Validate before calling

if (!client.proc?.stdin) throw new Error('stdin unavailable; (re)initialize');

Type guard

/** @param {object} c @returns {boolean} */
function hasStdin(c) { return Boolean(c.proc?.stdin); }

Try / catch

try {
  await client.request(method, params);
} catch (e) {
  if (/stdin is not available/.test(e.message)) { /* reinitialize */ }
  else throw e;
}

Prevention

When it happens

Trigger: Calling request()/notify() before initialize() has spawned the process (proc undefined), or after the codex process exited and stdin is gone. close() ends stdin, so a post-close request hits this.

Common situations: A race where handleExit fires (process crash) but a queued request still calls sendMessage; or invoking request before awaiting initialize().

Related errors


AI-assisted analysis of openai/codex-plugin-cc@db52e28f4d (2026-08-13). Data as JSON: /api/errors/46634f7c1d6263fc. Report an issue: GitHub.