chenhg5/cc-connect · error

claudeSession: stdin pipe

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.

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.

Appendix: 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)