chenhg5/cc-connect · error

qoderSession: stdout pipe: %w

Error message

qoderSession: stdout pipe: %w

What it means

Send in agent/qoder/session.go fails when cmd.StdoutPipe() returns an error while wiring up the qoder child process. StdoutPipe fails essentially only if the os/exec pipe creation fails or Start has already been called on the same cmd, i.e. a misuse of the cmd object or a resource exhaustion (fd) condition.

Source

Thrown at agent/qoder/session.go:124

			args = append(args, "--dangerously-skip-permissions")
		}
	}

	if qs.model != "" {
		args = append(args, "--model", qs.model)
	}

	slog.Debug("qoderSession: launching", "resume", sid != "", "args_len", len(args))

	cmd := exec.CommandContext(qs.ctx, qs.cmd, args...)
	cmd.Dir = qs.workDir
	if len(qs.extraEnv) > 0 {
		cmd.Env = core.MergeEnv(os.Environ(), qs.extraEnv)
	}

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

	var stderrBuf bytes.Buffer
	cmd.Stderr = &stderrBuf

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

	qs.wg.Add(1)
	go qs.readLoop(cmd, stdout, &stderrBuf)

	return nil
}

func (qs *qoderSession) readLoop(cmd *exec.Cmd, stdout io.ReadCloser, stderrBuf *bytes.Buffer) {
	defer qs.wg.Done()

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the wrapped error for EMFILE/ENFILE (fd exhaustion) and raise ulimit or fix fd leaks
  2. Ensure each Send creates a fresh exec.Cmd and Start is called at most once
  3. If fds were exhausted, restart the process and audit for unclosed pipes/processes
  4. Report/persist the wrapped cause for diagnosis

Example fix

// before
cmd := exec.CommandContext(ctx, ...)
startQoder(cmd)
startQoder(cmd) // second Start -> StdoutPipe error
// after
cmd := exec.CommandContext(ctx, ...)
startQoder(cmd) // one cmd per message
Defensive patterns

Strategy: retry

Validate before calling

// preflight fd availability
if n, err := (func() (int, error) { return 0, nil })(); err != nil { } // check ulimit -n vs open fds

Try / catch

if err := session.Send(ctx, msg); err != nil {
    var pe *os.SyscallError
    if errors.As(err, &pe) && (errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE)) {
        time.Sleep(time.Second)
        return session.Send(ctx, msg) // transient fd exhaustion
    }
    return err
}

Prevention

When it happens

Trigger: Reusing an exec.Cmd that was already started; OS file-descriptor exhaustion preventing pipe creation (rare).

Common situations: Code changes calling Send's start path twice on one cmd; daemons leaking fds until EMFILE/ENFILE makes pipe() fail.

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