NousResearch/hermes-agent · error · RuntimeError
codex app-server stdin not available
Error message
codex app-server stdin not available
What it means
RuntimeError('codex app-server stdin not available') from _send() (agent/transports/codex_app_server.py:305). It fires when self._proc.stdin is None, i.e. the subprocess was spawned without a stdin pipe, so there is no channel to write JSON-RPC frames to. This is a spawn-configuration bug in the caller, not a runtime failure of codex.
Source
Thrown at agent/transports/codex_app_server.py:305
def is_alive(self) -> bool:
return self._proc.poll() is None
# ---------- internals ----------
def _take_id(self) -> int:
# JSON-RPC ids only need to be unique per-connection. A simple
# monotonically increasing int is the common choice and matches what
# codex's own clients use.
rid = self._next_id
self._next_id += 1
return rid
def _send(self, obj: dict) -> None:
if self._closed:
raise RuntimeError("codex app-server client is closed")
if self._proc.stdin is None:
raise RuntimeError("codex app-server stdin not available")
try:
self._proc.stdin.write((json.dumps(obj) + "\n").encode("utf-8"))
self._proc.stdin.flush()
except (BrokenPipeError, ValueError) as exc:
raise RuntimeError(
f"codex app-server stdin closed unexpectedly: {exc}"
) from exc
def _read_stdout(self) -> None:
if self._proc.stdout is None:
return
try:
for line in iter(self._proc.stdout.readline, b""):
if not line:
break
line = line.strip()
if not line:
continueView on GitHub (pinned to c896c09c42)
Solutions
- Spawn the app-server with subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=...) so the JSON-RPC framing over stdio works.
- Fail fast: validate _proc.stdin is not None right after spawn instead of on first send.
- Reuse the client's own spawn helper rather than constructing the process manually.
Example fix
# before
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) # no stdin pipe
# after
proc = subprocess.Popen(
cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
) Defensive patterns
Strategy: validation
Validate before calling
import subprocess
def spawn_app_server(cmd: list[str]) -> subprocess.Popen:
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
assert proc.stdin is not None, "spawn must pipe stdin for JSON-RPC"
return proc Try / catch
try:
client.request("initialize", {})
except RuntimeError as exc:
if "stdin not available" in str(exc):
raise RuntimeError("respawn the app-server with stdin=PIPE") from exc
raise Prevention
- Always spawn stdio JSON-RPC servers with stdin=PIPE and stdout=PIPE.
- Validate both pipes immediately after Popen, not on first use.
- Prefer the client's own spawn helper over manual subprocess construction.
When it happens
Trigger: The Popen call that created the codex app-server process lacked stdin=PIPE (or explicitly set stdin=DEVNULL/None), then any request/notify hits the guard immediately.
Common situations: A custom spawn path (test harness, alternate launcher) copies a generic subprocess helper that only pipes stdout/stderr; refactoring the spawn code drops the stdin pipe; Windows-specific spawn flags accidentally overriding stdin.
Related errors
- codex app-server method {method!r} timed out after {timeout}
- already initialized
- codex app-server error {code}: {message}
- codex app-server client is closed
- codex app-server stdin closed unexpectedly: {exc}
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/f48b91b3f1c15c7f.
Report an issue: GitHub.