chenhg5/cc-connect · critical

%s write timed out

Error message

%s write timed out

What it means

Returned by `writeJSONWithTimeout` when writing a JSON-RPC payload to the codex app-server's stdin does not complete within the timeout. The adapter logs a warning and calls `abortTransport()`, killing the child process and closing the session — so this error also tears down the session. The message is `<method> write timed out`.

Source

Thrown at agent/codex/appserver_session.go:1676

}

func (s *appServerSession) writeJSONWithTimeout(method string, v any, timeout time.Duration) error {
	done := make(chan error, 1)
	go func() {
		done <- s.writeJSON(v)
	}()

	timer := time.NewTimer(timeout)
	defer timer.Stop()

	ctxDone := s.contextDone()
	select {
	case err := <-done:
		return err
	case <-ctxDone:
		return s.contextErr()
	case <-timer.C:
		err := fmt.Errorf("%s write timed out", method)
		slog.Warn("codex app-server write timed out, closing session", "method", method, "timeout", timeout)
		s.abortTransport()
		return err
	}
}

func (s *appServerSession) contextDone() <-chan struct{} {
	if s.ctx == nil {
		return nil
	}
	return s.ctx.Done()
}

func (s *appServerSession) contextErr() error {
	if s.ctx == nil {
		return context.Canceled
	}
	if err := s.ctx.Err(); err != nil {

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Recreate the codex session — `abortTransport` already killed the process, the session is unusable.
  2. Check whether the codex process hangs on startup (run it manually with the same args).
  3. Reduce payload size (huge context/instructions) that can fill the pipe buffer.
  4. Check host resource pressure (CPU, memory, stopped processes).
  5. Upgrade codex to a version without known stdin-handling deadlocks.

Example fix

// caller side: treat write timeout as fatal for the session
if err := sess.request("turn/create", params, &out); err != nil {
    if strings.Contains(err.Error(), "write timed out") {
        // before: retry on dead session
        // after: rebuild session
        sess = newAppServerSession(...)
    }
}
Defensive patterns

Strategy: fallback

Validate before calling

// check the session is alive and process running before writing
if !sess.Alive() {
    return fmt.Errorf("codex session dead; restart before requesting")
}

Try / catch

if err := sess.request(method, params, out); err != nil {
    if strings.Contains(err.Error(), "write timed out") {
        slog.Warn("codex write timed out; session was aborted")
        // session is dead — recreate from scratch
        return recreateSessionAndRetry(ctx, method, params, out)
    }
    return err
}

Prevention

When it happens

Trigger: `requestWithTimeout` (or notify with timeout) calls `writeJSONWithTimeout`; the goroutine writing to the child's stdin pipe blocks past the deadline because the app-server stopped reading stdin (full pipe, hung process) or the OS pipe is stalled.

Common situations: Codex app-server deadlocked or crashed while the OS pipe buffer is full; stdin buffer exhausted by a large payload; heavy system load stalling the write; child process stopped (SIGSTOP) or PID reaped unexpectedly.

Understand the failure class

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/000abb8ac372d370. Report an issue: GitHub.