chenhg5/cc-connect · error
read stdout: %w
Error message
read stdout: %w
What it means
The Codex session's readLoop goroutine scans the agent process's stdout with a line scanner; when that scanner returns an error (process exit, closed pipe, I/O failure), it logs it and emits a core.EventError wrapping the underlying error. This is how the session surfaces that the Codex app-server's stdout stream broke. Note that a normal process exit produces EOF here, so this often appears after the agent process dies unexpectedly.
Source
Thrown at agent/codex/session.go:338
if err := readJSONLines(stdout, func(line []byte) error {
lineText := string(line)
if lineText == "" {
return nil
}
slog.Debug("codexSession: raw", "line", truncate(lineText, 500))
var raw map[string]any
if err := json.Unmarshal(line, &raw); err != nil {
slog.Debug("codexSession: non-JSON line", "line", lineText)
return nil
}
cs.handleEvent(raw)
return nil
}); err != nil {
slog.Error("codexSession: read stdout error", "error", err)
evt := core.Event{Type: core.EventError, Error: fmt.Errorf("read stdout: %w", err)}
select {
case cs.events <- evt:
case <-cs.ctx.Done():
return
}
}
}
func readJSONLines(r io.Reader, handle func([]byte) error) error {
reader := bufio.NewReader(r)
for {
line, err := reader.ReadBytes('\n')
if errors.Is(err, io.EOF) && len(line) == 0 {
return nil
}
if err != nil && !errors.Is(err, io.EOF) {
return errView on GitHub (pinned to 4000b2338a)
Solutions
- Check that the codex CLI binary is on PATH, executable, and runs (`codex --version`) — early exit is the most common cause.
- Verify codex authentication (`codex login` / auth config) so the process does not die immediately after startup.
- Inspect session logs for the preceding `codexSession: read stdout error` slog entry and any stderr output from the process to find the root exit cause.
- If the session is stale, create a new session via StartSession; the events channel is closed/drained after this error.
- Check system resource limits (ulimit, memory) if the process is being killed under load.
Example fix
// before: process exits due to missing auth and stdout EOF surfaces as an opaque error
// after: verify the binary works and is authenticated before creating a session
if err := exec.Command("codex", "login", "status").Run(); err != nil {
return fmt.Errorf("codex not authenticated: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// before creating a session
cmd := exec.Command("codex", "--version")
if err := cmd.Run(); err != nil {
return fmt.Errorf("codex binary not runnable: %w", err)
} Type guard
func isStdoutReadError(evt core.Event) bool {
return evt.Type == core.EventError && evt.Error != nil && strings.Contains(evt.Error.Error(), "read stdout:")
} Try / catch
go func() {
for evt := range sess.Events() {
if evt.Type == core.EventError && strings.Contains(evt.Error.Error(), "read stdout:") {
slog.Warn("codex stream broke, recreating session", "err", evt.Error)
// fall back: recreate session and resend pending message
}
}
}() Prevention
- Pre-flight check the codex binary and authentication before opening sessions
- Monitor stderr/logs for early process exit causes
- Set resource limits (ulimit, memory) appropriate for long-lived child processes
- Handle the error event by recreating the session instead of reusing the dead one
When it happens
Trigger: The codex process terminates or crashes while a session is active; the stdout pipe is closed or broken; an I/O read error occurs on the scanner (bufio.Scanner/ReadString failure) inside readLoop.
Common situations: The codex binary segfaults or is OOM-killed mid-session; the user's shell/environment kills the child process; codex exits early due to bad flags or auth so stdout closes while readLoop is still scanning; system resource limits break the pipe.
Related errors
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/8f76909040055e94.
Report an issue: GitHub.