chenhg5/cc-connect · error
stdin pipe: %w
Error message
stdin pipe: %w
What it means
startRPC builds the exec.Cmd for the pi RPC subprocess and requests an stdin pipe via cmd.StdinPipe(). If the OS returns an error creating the pipe, it is wrapped as 'stdin pipe: %w'. This is a very low-level failure — pipe allocation happens almost exclusively inside os/exec.
Source
Thrown at agent/pi/session.go:196
args = append(args, "--model", s.model)
}
if s.thinking != "" {
args = append(args, "--thinking", s.thinking)
}
slog.Debug("piSession: starting RPC", "cmd", s.cmd, "args", args)
cmd := exec.CommandContext(s.ctx, s.cmd, args...)
cmd.Dir = s.workDir
env := os.Environ()
if len(s.extraEnv) > 0 {
env = core.MergeEnv(env, s.extraEnv)
}
cmd.Env = env
stdinPipe, err := cmd.StdinPipe()
if err != nil {
return fmt.Errorf("stdin pipe: %w", err)
}
s.rpcStdin = stdinPipe
s.rpcCmd = cmd
stdout, err := cmd.StdoutPipe()
if err != nil {
return fmt.Errorf("stdout pipe: %w", err)
}
cmd.Stderr = &s.stderrBuf
prepareCmdForKill(cmd)
if err := cmd.Start(); err != nil {
return fmt.Errorf("start: %w", err)
}
s.wg.Add(1)
go s.readLoopRPC(stdout)View on GitHub (pinned to 4000b2338a)
Solutions
- Check for leaked pi/zombie subprocesses from prior sessions and kill them; investigate why sessions aren't being Stop()'d.
- Raise the file descriptor limit: `ulimit -n 4096` or set LimitNOFILE=4096 in the systemd unit.
- Restart cc-connect to release leaked descriptors, then fix the leak that exhausted them.
- Inspect the wrapped cause (%w) to confirm EMFILE/ENFILE and monitor open fds with `ls /proc/<pid>/fd | wc -l`.
Example fix
// systemd unit, before [Service] ExecStart=/usr/local/bin/cc-connect // after [Service] LimitNOFILE=8192 ExecStart=/usr/local/bin/cc-connect
Defensive patterns
Strategy: retry
Validate before calling
var lim syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err == nil && lim.Cur < 1024 {
log.Printf("low fd limit (%d); raise before spawning many pi sessions", lim.Cur)
}
nFds, _ := countOpenFds(os.Getpid())
if nFds > int(float64(lim.Cur)*0.8) {
return fmt.Errorf("fd usage %d/%d too high to spawn pi safely", nFds, lim.Cur)
} Try / catch
sess, err := agent.StartSession(ctx, opts)
if err != nil && strings.Contains(err.Error(), "stdin pipe") {
log.Printf("fd/pipe allocation failed; check ulimit -n and leaked pi processes, then retry")
return fmt.Errorf("resource exhaustion starting pi: %w", err)
} Prevention
- Set LimitNOFILE (systemd) or ulimit -n generously for the daemon.
- Stop() sessions promptly; audit for zombie pi processes holding pipes.
- Monitor open fd counts and alert before exhaustion.
When it happens
Trigger: startRPC (called from newPiSession) when cmd.StdinPipe() fails — practically only on OS resource exhaustion: file descriptor limit hit (too many open files/processes), or the os/exec package already reported the command started/waited state.
Common situations: Daemons leaking subprocesses/pipes until ulimit -n is exhausted; containers with tiny fd limits; runaway session creation loops leaving zombie pi processes holding descriptors.
Related errors
- stdout pipe: %w
- claudeSession: stdin pipe: %w
- claudeSession: stdout pipe: %w
- codex app-server stdin pipe: %w
- codex app-server stdout pipe: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/cefe45fb1379af3d.
Report an issue: GitHub.