chenhg5/cc-connect · error

acp: probe stdin pipe: %w

Error message

acp: probe stdin pipe: %w

What it means

probeSpawn (agent/acp/list_sessions.go) launches the ACP agent briefly over stdio to enumerate existing sessions. This error occurs when os/exec's StdinPipe() fails, before the process starts — an OS-level pipe allocation failure, not an agent problem. ListSessions propagates it and aborts the listing.

Source

Thrown at agent/acp/list_sessions.go:77

type acpSessionListEntry struct {
	SessionID string `json:"sessionId"`
	Cwd       string `json:"cwd"`
	Title     string `json:"title,omitempty"`
	UpdatedAt string `json:"updatedAt,omitempty"`
}

// probeSpawn launches `<cmd> <args...>`, sets up a JSON-RPC transport
// and starts its readLoop. The caller owns the returned `teardown`
// func and must invoke it to reap the child process.
func (a *Agent) probeSpawn(ctx context.Context, cwd string) (*transport, *bytes.Buffer, func(), error) {
	allArgs := append(append([]string{}, a.cliExtraArgs...), a.args...)
	cmd := exec.CommandContext(ctx, a.cmd, allArgs...)
	cmd.Dir = cwd
	cmd.Env = core.MergeEnv(os.Environ(), a.extraEnv)

	stdin, err := cmd.StdinPipe()
	if err != nil {
		return nil, nil, nil, fmt.Errorf("acp: probe stdin pipe: %w", err)
	}
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, nil, nil, fmt.Errorf("acp: probe stdout pipe: %w", err)
	}
	var stderrBuf bytes.Buffer
	cmd.Stderr = io.MultiWriter(&stderrBuf)

	if err := cmd.Start(); err != nil {
		return nil, nil, nil, fmt.Errorf("acp: probe start %s: %w", a.cmd, err)
	}

	// The server-request handler needs to reference `tr` itself in order
	// to respondError; declare via var so the closure captures the
	// variable (which is assigned to a *transport below) rather than an
	// uninitialised copy.
	var tr *transport
	tr = newTransport(stdout, stdin,

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Raise the file-descriptor limit: `ulimit -n 4096` or systemd LimitNOFILE=65536, then restart cc-connect.
  2. Check for fd leaks with `ls /proc/<pid>/fd | wc -l` and restart the daemon if the count is near the limit.
  3. Reduce concurrent ListSessions/agent spawn operations.
  4. If in a container, raise nofile limits in the container runtime configuration.

Example fix

// before (systemd unit)
[Service]
ExecStart=/usr/bin/cc-connect
// after
[Service]
ExecStart=/usr/bin/cc-connect
LimitNOFILE=65536
Defensive patterns

Strategy: retry

Validate before calling

// before spawning, ensure headroom for pipes/fds:
var lim syscall.Rlimit
syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)
if lim.Cur < 1024 {
    return errors.New("file descriptor limit too low for agent probes; raise ulimit -n")
}

Try / catch

sessions, _, err := a.ListSessions(ctx)
if err != nil && strings.Contains(err.Error(), "probe stdin pipe") {
    // fd exhaustion — wait and retry after limits/restart
    slog.Warn("acp: probe pipe failed, retrying later", "err", err)
    time.Sleep(backoff)
    sessions, _, err = a.ListSessions(ctx)
}

Prevention

When it happens

Trigger: cmd.StdinPipe() returns an error inside probeSpawn during ListSessions — typically resource exhaustion: the process hit its file-descriptor limit (ulimit -n), or the OS refused new pipe allocations.

Common situations: Long-running daemons leaking file descriptors; low ulimit -n on servers; containers with small fd limits; spawning many concurrent ListSessions probes.

Related errors


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