chenhg5/cc-connect · error

claudeSession: stdin pipe: %w

Error message

claudeSession: stdin pipe: %w

What it means

newClaudeSession wraps the error returned by cmd.StdinPipe() when the os/exec package cannot create the stdin pipe for the spawned `claude` process. This almost always means an OS-level resource problem (file descriptor exhaustion) or calling StdinPipe after Start, which this code never does. The session is aborted (context cancelled) and never returned.

Source

Thrown at agent/claudecode/session.go:427

	var providerEnvSnapshot []string
	for _, e := range env {
		for _, prefix := range []string{"ANTHROPIC_", "CLAUDE_", "AWS_", "NO_PROXY", "DISABLE_"} {
			if strings.HasPrefix(e, prefix) {
				providerEnvSnapshot = append(providerEnvSnapshot, e)
				break
			}
		}
	}
	slog.Debug("claudeSession: spawn details",
		"bin", cliBin,
		"allArgs", core.RedactArgs(allArgs),
		"model", model,
		"providerEnv", core.RedactEnv(providerEnvSnapshot))

	stdin, err := cmd.StdinPipe()
	if err != nil {
		cancel()
		return nil, fmt.Errorf("claudeSession: stdin pipe: %w", err)
	}

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		cancel()
		return nil, fmt.Errorf("claudeSession: stdout pipe: %w", err)
	}

	var stderrBuf bytes.Buffer
	cmd.Stderr = &stderrBuf

	// 🔴 /stop「杀不死」的根因修复(2026-07-29)。
	//
	// 症状:taskkill /T /F 报成功,Close() 却在 10 秒后返回
	// "process tree (pid N) still alive 10s after SIGKILL reported success",
	// engine 于是认定 teardown 失败 —— 用户按了 /stop,却像在跟另一个 session 说话。
	//
	// 机制:上面这行把 stderr 接到 *bytes.Buffer(不是 *os.File),os/exec 因此会

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check and raise the file descriptor limit (ulimit -n / systemd LimitNOFILE) on the host running cc-connect
  2. Audit for fd leaks: lsof -p <cc-connect-pid> | wc -l and compare to ulimit -n; restart the daemon to reclaim fds
  3. Reduce concurrent sessions (each session consumes multiple pipes) or enable session recycling
  4. Retry session creation once fds are freed; the error is wrapped so inspect %w for the underlying os.SyscallError

Example fix

// before
// daemon started with default LimitNOFILE=1024, hundreds of sessions leak fds
// after
# systemd unit
[Service]
LimitNOFILE=65536
Defensive patterns

Strategy: fallback

Validate before calling

import "syscall"

func fdsAvailable(min int) bool {
    var lim syscall.Rlimit
    if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {
        return false
    }
    return lim.Cur > uint64(min)
}

Try / catch

sess, err := agent.StartSession(ctx, prompt)
if err != nil && strings.Contains(err.Error(), "stdin pipe") {
    // fd exhaustion: wait/backoff, then retry once
    time.Sleep(2 * time.Second)
    sess, err = agent.StartSession(ctx, prompt)
}
if err != nil { return err }

Prevention

When it happens

Trigger: newClaudeSession calls cmd.StdinPipe() and it returns an error — practically only when the process has exhausted file descriptors (ulimit -n reached, fd leak elsewhere) or the OS denies pipe allocation.

Common situations: Long-running cc-connect daemons that leaked sockets/files until hitting the nofile ulimit; containers with very low fd limits; system-wide pipe/memory pressure.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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