chenhg5/cc-connect · error
codex app-server stdin pipe: %w
Error message
codex app-server stdin pipe: %w
What it means
This error wraps a failure from cmd.StdinPipe() while starting the codex app-server child process. Obtaining the stdin pipe is part of the child-process bootstrap in the codex agent session; if the OS refuses to allocate the pipe (rare, usually fd exhaustion), the session cannot send JSON-RPC requests to the app-server. The library wraps the OS error with context so callers know which pipe stage failed.
Source
Thrown at agent/codex/appserver_session.go:266
if provider := strings.TrimSpace(s.modelProvider); provider != "" {
args = append(args, "-c", fmt.Sprintf("model_provider=%q", provider))
}
if baseURL := strings.TrimSpace(s.baseURL); baseURL != "" {
args = append(args, "-c", fmt.Sprintf("openai_base_url=%q", baseURL))
}
cmd := exec.CommandContext(s.ctx, "codex", args...)
cmd.Dir = s.workDir
env := append([]string(nil), s.extraEnv...)
if s.codexHome != "" {
env = append(env, "CODEX_HOME="+s.codexHome)
}
if len(env) > 0 {
cmd.Env = core.MergeEnv(os.Environ(), env)
}
stdin, err := cmd.StdinPipe()
if err != nil {
return fmt.Errorf("codex app-server stdin pipe: %w", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return fmt.Errorf("codex app-server stdout pipe: %w", err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
return fmt.Errorf("codex app-server stderr pipe: %w", err)
}
if err := cmd.Start(); err != nil {
return fmt.Errorf("codex app-server start: %w", err)
}
s.procMu.Lock()
s.cmd = cmd
s.stdin = stdin
s.procMu.Unlock()
View on GitHub (pinned to 4000b2338a)
Solutions
- Raise the file-descriptor limit (ulimit -n 4096 or systemd LimitNOFILE=4096) for the cc-connect process.
- Check for fd leaks: lsof -p <pid> | wc -l; ensure closed sessions release pipes.
- Restart the daemon to release leaked descriptors as an immediate mitigation.
Example fix
// before
stdin, err := cmd.StdinPipe()
if err != nil {
return fmt.Errorf("codex app-server stdin pipe: %w", err)
}
// after
// no code change possible to fix EMFILE; ensure enclosing startup retries
// after caller raises RLIMIT_NOFILE:
if err := start(); err != nil && errors.Is(err, syscall.EMFILE) {
return fmt.Errorf("file descriptor limit reached; raise RLIMIT_NOFILE: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check fd headroom before spawning the app-server
var lim syscall.Rlimit
syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)
openFDs := countOpenFDs() // e.g. via /proc/self/fd
if openFDs > int(lim.Cur)-64 {
return errors.New("file descriptor limit nearly exhausted; raise RLIMIT_NOFILE")
} Try / catch
if err := session.Start(ctx); err != nil {
var syscallErr *os.SyscallError
if errors.As(err, &syscallErr) && (errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE)) {
return fmt.Errorf("fd limit reached; raise RLIMIT_NOFILE: %w", err)
}
return err
} Prevention
- Raise RLIMIT_NOFILE (ulimit -n / systemd LimitNOFILE) for long-running daemons.
- Close sessions deterministically so pipes are released.
- Monitor open fd counts and alert before exhaustion.
- Restart daemons on a schedule if fd growth is expected.
When it happens
Trigger: Calling StartSession/ensureStarted on the codex agent, which executes the appServerSession process-startup path; cmd.StdinPipe() returns a non-nil error — almost always because the process has exhausted its file-descriptor limit (EMFILE/ENFILE).
Common situations: ulimit -n too low on a host running many sessions; file-descriptor leak in a long-running daemon accumulating child processes; container with a low RLIMIT_NOFILE.
Related errors
- codex app-server stdout pipe: %w
- codex app-server stderr pipe: %w
- copilot probe: stdout pipe: %w
- geminiSession: stdout pipe: %w
- kimiSession: stdout pipe: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/038812bb21627189.
Report an issue: GitHub.