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 err

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check that the codex CLI binary is on PATH, executable, and runs (`codex --version`) — early exit is the most common cause.
  2. Verify codex authentication (`codex login` / auth config) so the process does not die immediately after startup.
  3. 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.
  4. If the session is stale, create a new session via StartSession; the events channel is closed/drained after this error.
  5. 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

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.