app-server UDS closes standard WebSocket-over-UDS handshake
Summary
codex app-server --listen unix://... starts and creates a Unix socket in codex-cli 0.125.0, but a standard WebSocket-over-UDS client is closed during the HTTP upgrade with socket hang up.
Repro
Start app-server:
codex app-server --listen unix:///home/kevin/codex.sock
The socket exists and is owned by Codex:
srw-------. 1 kevin kevin 0 Apr 26 11:52 /home/kevin/codex.sock
ss: users:(("codex",pid=1096289,fd=20)) LISTEN /home/kevin/codex.sock
Connect with a Node ws client over that UDS path:
import { createConnection } from "node:net";
import { WebSocket } from "ws";
const ws = new WebSocket("ws://localhost/rpc", {
createConnection: () => createConnection({ path: "/home/kevin/codex.sock" }),
perMessageDeflate: false,
});
ws.on("open", () => console.log("open"));
ws.on("error", (err) => console.log("error", err.message));
ws.on("close", (code, reason) => console.log("close", code, reason.toString()));
Observed:
error socket hang up
close 1006
The same error appears when using task-runner's Codex UDS transport:
TASK_RUNNER_CODEX_UDS_PATH=~/codex.sock node apps/cli/dist/cli.js run --agent planner "Testing, respond OK"
# -- attempt 1 --
# socket hang up
Troubleshooting notes
I reproduced this outside task-runner with a direct Node ws probe, so this is not specific to task-runner JSON-RPC handling. I also reproduced against a fresh temporary app-server socket.
With tracing enabled on the temporary app-server:
RUST_LOG=codex_app_server=trace,tokio_tungstenite=trace \
CODEX_HOME=/tmp/codex-home \
codex app-server --listen unix:///tmp/codex-probe.sock
Codex logged:
INFO codex_app_server::transport::unix_socket: app-server control socket listening socket_path=/tmp/.../codex-probe.sock
WARN codex_app_server::transport::websocket: websocket receive error: WebSocket protocol error: Encountered invalid opcode: 7
That looks like the server is treating the HTTP upgrade request byte G from GET /rpc HTTP/1.1 as an already-established websocket frame, rather than completing the websocket HTTP Upgrade handshake.
Expected
The UDS app-server transport should accept a standard websocket HTTP Upgrade handshake over the Unix socket, matching the app-server README description of unix://PATH and the existing client_async("ws://localhost/rpc", stream) style test coverage.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗