-
Notifications
You must be signed in to change notification settings - Fork 10.3k
codex-app-server-sdk: StdioTransport crashes on prompts >64 KiB due to Python asyncio StreamReader limit #16554
Description
Summary
The codex-app-server-sdk Python package crashes with CodexTransportError: failed reading from stdio transport when a single JSON-RPC message (typically turn/start with a large prompt) exceeds ~65,536 bytes.
Root Cause
StdioTransport.connect() spawns the codex app-server subprocess via asyncio.create_subprocess_exec() without specifying the limit parameter:
# codex_app_server_sdk/transport.py, line 70-78
self._proc = await asyncio.wait_for(
asyncio.create_subprocess_exec(
*self._command,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL,
...
),
timeout=self._connect_timeout,
)Python's asyncio.StreamReader defaults to a 64 KiB line limit (asyncio.streams._DEFAULT_LIMIT = 65536). The Codex app-server echoes input content in its JSON-RPC response lines on stdout. When a response line exceeds 64 KiB, StreamReader.readline() raises LimitOverrunError, which StdioTransport.recv() catches and re-raises as CodexTransportError("failed reading from stdio transport").
The app-server itself handles large prompts fine (verified by communicating with it directly).
Reproduction
import asyncio
from codex_app_server_sdk import CodexClient, ThreadConfig, TurnOverrides
async def main():
client = CodexClient.connect_stdio(inactivity_timeout=30.0)
await client.start()
# This prompt produces a turn/start message >65536 bytes
prompt = "Reply with 'ok'. " + ("x" * 80000)
async for step in client.chat(
prompt,
thread_config=ThreadConfig(
model="gpt-5.4-mini",
base_instructions="Reply ok.",
sandbox="read-only",
approval_policy="never",
),
):
print(step.text)
asyncio.run(main())
# -> CodexTransportError: failed reading from stdio transportFix
Pass limit=1_048_576 (1 MB) to asyncio.create_subprocess_exec() in StdioTransport.connect():
self._proc = await asyncio.wait_for(
asyncio.create_subprocess_exec(
*self._command,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL,
cwd=self._cwd,
env=self._env,
limit=1_048_576, # 1 MB instead of default 64 KiB
),
timeout=self._connect_timeout,
)Verified working with prompts up to 200K characters after this change.
Environment
codex-app-server-sdkinstalled via pipcodex-cli0.118.0- Python 3.13
- macOS (Darwin 25.3.0)