chenhg5/cc-connect · error

copilotSession: stdin pipe: %w

Error message

copilotSession: stdin pipe: %w

What it means

newCopilotSession builds the exec.Command for the copilot CLI and obtains an stdin pipe so the RPC client can write JSON-RPC requests. If child.StdinPipe() returns an error the context is cancelled and construction aborts with "copilotSession: stdin pipe: %w". This means the OS pipe could not be created and the session can never be started.

Source

Thrown at agent/copilot/session.go:109

	args := append(append([]string{}, extraArgs...), "--headless", "--stdio", "--no-auto-update")

	slog.Debug("copilotSession: starting", "bin", cliBin, "args", args, "dir", workDir)

	child := exec.CommandContext(sessionCtx, cliBin, args...)
	child.Dir = workDir
	prepareCmdForKill(child)

	env := os.Environ()
	if len(extraEnv) > 0 {
		env = core.MergeEnv(env, extraEnv)
	}
	child.Env = env

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

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

	var stderrBuf bytes.Buffer
	child.Stderr = &stderrBuf

	if err := child.Start(); err != nil {
		cancel()
		return nil, fmt.Errorf("copilotSession: start: %w", err)
	}

	cs := &copilotSession{
		cmd:                child,

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check for fd leaks — run `lsof -p <pid>` and raise the limit (ulimit -n) in the daemon environment
  2. Ensure each session creates a fresh exec.Cmd; never reuse one across sessions
  3. Restart the daemon if the fd table is exhausted; the error is usually transient at the OS level
  4. If it persists in containers, raise the nofile limit in the container runtime config

Example fix

// before: reusing one exec.Cmd per request
cmd := sharedCmd
s, err := newCopilotSession(ctx, cmd, ...)
// after: fresh command per session
s, err := newCopilotSession(ctx, exec.CommandContext(ctx, binPath, args...), ...)
Defensive patterns

Strategy: try-catch

Try / catch

sess, err := StartSession(ctx, cfg, resumeID)
if err != nil {
    if strings.Contains(err.Error(), "stdin pipe") {
        slog.Error("copilot: cannot create stdin pipe (fd exhaustion?)", "err", err)
    }
    return fmt.Errorf("start session: %w", err)
}

Prevention

When it happens

Trigger: StartSession → newCopilotSession where StdinPipe() fails — practically only under fd exhaustion, a closed/invalid os.Pipe environment, or an exec.Cmd in an invalid state (already started, or Wait called previously).

Common situations: Process file-descriptor exhaustion (ulimit, leaked pipes in a long-running daemon); reusing a single exec.Cmd for multiple sessions; running in a container with a tiny fd limit.

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/db0348c5ab9aa96c. Report an issue: GitHub.