chenhg5/cc-connect · error

kimiSession: stdout pipe: %w

Error message

kimiSession: stdout pipe: %w

What it means

kimiSession.Send builds the exec.Cmd for the kimi CLI and calls cmd.StdoutPipe(); if the OS refuses to allocate the pipe, Send aborts with `kimiSession: stdout pipe: %w` wrapping the underlying error. StdoutPipe fails almost exclusively when file descriptors are exhausted or when cmd.Stdout/cmd.Stderr was already assigned (pipes and explicit writers are mutually exclusive in exec).

Source

Thrown at agent/kimi/session.go:213

		}
	}()

	slog.Debug("kimiSession: launching",
		"resume", ks.CurrentSessionID() != "",
		"supports_print", ks.flagSupport.Print,
		"args", core.RedactArgs(args))
	cmd := exec.CommandContext(ctx, ks.cmd, args...)
	cmd.WaitDelay = 1 * time.Second
	cmd.Dir = ks.workDir
	env := os.Environ()
	if len(ks.extraEnv) > 0 {
		env = core.MergeEnv(env, ks.extraEnv)
	}
	cmd.Env = env

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

	var stderrBuf bytes.Buffer
	cmd.Stderr = &stderrBuf

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

	started = true
	ks.wg.Add(1)
	go func() {
		defer cancel()
		ks.readLoop(ctx, cmd, stdout, &stderrBuf, append(imageRefs, fileRefs...))
	}()

	return nil
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check fd usage (`ls /proc/<pid>/fd | wc -l`); raise the limit (ulimit -n / systemd LimitNOFILE=65536) or fix the descriptor leak.
  2. Restart the cc-connect daemon to release leaked descriptors.
  3. Audit the kimi package for cmd.Stdout/cmd.Stderr assignments that run before StdoutPipe and remove duplicates.
  4. In containers, set the nofile rlimit explicitly in the deployment spec.

Example fix

// before (bug: Stdout set before piping)
cmd.Stdout = os.Stdout
stdout, err := cmd.StdoutPipe() // exec: Stdout already set

// after
stdout, err := cmd.StdoutPipe()
if err != nil {
    return fmt.Errorf("kimiSession: stdout pipe: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// check fd headroom before starting more sessions
fds, _ := filepath.Glob("/proc/self/fd/*")
if len(fds) > 900 { // near default 1024 limit
    return errors.New("too many open fds; refusing to start new session")
}

Try / catch

if err := sess.Send(prompt, msgID, nil, nil); err != nil {
    if strings.Contains(err.Error(), "stdout pipe") {
        slog.Warn("pipe allocation failed, retrying after cleanup", "err", err)
        runtime.GC() // release finalized handles
        err = sess.Send(prompt, msgID, nil, nil)
    }
    return err
}

Prevention

When it happens

Trigger: Send() called when the process hit its RLIMIT_NOFILE / fd limit; or a code path assigned cmd.Stdout (or cmd.Stderr) before StdoutPipe is invoked, producing exec's 'Stdout already set' error.

Common situations: Daemons running many concurrent agent sessions leaking pipes/fds until the limit; containers with low fd limits (ulimit -n 256); a refactoring bug that sets cmd.Stdout elsewhere in the package.

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