{"record":{"id":"da9aab7375f3c59a","repo":"chenhg5/cc-connect","slug":"claudesession-stdin-pipe-w","errorCode":null,"errorMessage":"claudeSession: stdin pipe: %w","messagePattern":"claudeSession: stdin pipe: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/claudecode/session.go","lineNumber":427,"sourceCode":"\tvar providerEnvSnapshot []string\n\tfor _, e := range env {\n\t\tfor _, prefix := range []string{\"ANTHROPIC_\", \"CLAUDE_\", \"AWS_\", \"NO_PROXY\", \"DISABLE_\"} {\n\t\t\tif strings.HasPrefix(e, prefix) {\n\t\t\t\tproviderEnvSnapshot = append(providerEnvSnapshot, e)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tslog.Debug(\"claudeSession: spawn details\",\n\t\t\"bin\", cliBin,\n\t\t\"allArgs\", core.RedactArgs(allArgs),\n\t\t\"model\", model,\n\t\t\"providerEnv\", core.RedactEnv(providerEnvSnapshot))\n\n\tstdin, err := cmd.StdinPipe()\n\tif err != nil {\n\t\tcancel()\n\t\treturn nil, fmt.Errorf(\"claudeSession: stdin pipe: %w\", err)\n\t}\n\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\tcancel()\n\t\treturn nil, fmt.Errorf(\"claudeSession: stdout pipe: %w\", err)\n\t}\n\n\tvar stderrBuf bytes.Buffer\n\tcmd.Stderr = &stderrBuf\n\n\t// 🔴 /stop「杀不死」的根因修复（2026-07-29）。\n\t//\n\t// 症状：taskkill /T /F 报成功，Close() 却在 10 秒后返回\n\t// \"process tree (pid N) still alive 10s after SIGKILL reported success\"，\n\t// engine 于是认定 teardown 失败 —— 用户按了 /stop，却像在跟另一个 session 说话。\n\t//\n\t// 机制：上面这行把 stderr 接到 *bytes.Buffer（不是 *os.File），os/exec 因此会","sourceCodeStart":409,"sourceCodeEnd":445,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/claudecode/session.go#L409-L445","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check and raise the file descriptor limit (ulimit -n / systemd LimitNOFILE) on the host running cc-connect","Audit for fd leaks: lsof -p <cc-connect-pid> | wc -l and compare to ulimit -n; restart the daemon to reclaim fds","Reduce concurrent sessions (each session consumes multiple pipes) or enable session recycling","Retry session creation once fds are freed; the error is wrapped so inspect %w for the underlying os.SyscallError"],"exampleFix":"// before\n// daemon started with default LimitNOFILE=1024, hundreds of sessions leak fds\n// after\n# systemd unit\n[Service]\nLimitNOFILE=65536","handlingStrategy":"fallback","validationCode":"import \"syscall\"\n\nfunc fdsAvailable(min int) bool {\n    var lim syscall.Rlimit\n    if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim); err != nil {\n        return false\n    }\n    return lim.Cur > uint64(min)\n}","typeGuard":null,"tryCatchPattern":"sess, err := agent.StartSession(ctx, prompt)\nif err != nil && strings.Contains(err.Error(), \"stdin pipe\") {\n    // fd exhaustion: wait/backoff, then retry once\n    time.Sleep(2 * time.Second)\n    sess, err = agent.StartSession(ctx, prompt)\n}\nif err != nil { return err }","preventionTips":["Raise LimitNOFILE/ulimit -n for the daemon (systemd unit or shell profile)","Monitor open fd count of the cc-connect process and alert near the limit","Bound concurrent agent sessions in configuration","Restart the daemon on a schedule if it handles very high session churn"],"tags":["go","os-exec","process-spawn","file-descriptors"],"backgroundTag":"file-open-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}