{"record":{"id":"0a2ad0e826c291da","repo":"chenhg5/cc-connect","slug":"stdout-pipe-w","errorCode":null,"errorMessage":"stdout pipe: %w","messagePattern":"stdout pipe: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/pi/session.go","lineNumber":203,"sourceCode":"\n\tcmd := exec.CommandContext(s.ctx, s.cmd, args...)\n\tcmd.Dir = s.workDir\n\tenv := os.Environ()\n\tif len(s.extraEnv) > 0 {\n\t\tenv = core.MergeEnv(env, s.extraEnv)\n\t}\n\tcmd.Env = env\n\n\tstdinPipe, err := cmd.StdinPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"stdin pipe: %w\", err)\n\t}\n\ts.rpcStdin = stdinPipe\n\ts.rpcCmd = cmd\n\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"stdout pipe: %w\", err)\n\t}\n\tcmd.Stderr = &s.stderrBuf\n\n\tprepareCmdForKill(cmd)\n\n\tif err := cmd.Start(); err != nil {\n\t\treturn fmt.Errorf(\"start: %w\", err)\n\t}\n\n\ts.wg.Add(1)\n\tgo s.readLoopRPC(stdout)\n\n\t// Pi's RPC protocol does not push a \"session\" event on stdout — the only\n\t// way to learn the session id is to send {\"type\":\"get_state\"} and parse\n\t// the matching response in handleEvent. We probe immediately after spawn\n\t// so that newPiSession's wait on rpcReady only unblocks once the id has\n\t// been stored. readLoopRPC closes rpcReady as soon as sessionIDReady()\n\t// flips to true (which happens after handleEvent processes the response),","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/pi/session.go#L185-L221","documentation":"startRPC requests an stdout pipe for the pi RPC subprocess via cmd.StdoutPipe(); any OS error creating it is wrapped as 'stdout pipe: %w'. Like the stdin-pipe error, this is a near-impossible-in-practice OS-level failure that indicates resource exhaustion or exec package misuse.","triggerScenarios":"startRPC (called from newPiSession) when cmd.StdoutPipe() fails — OS-level pipe/fd allocation failure, e.g. file descriptor limits (EMFILE/ENFILE) or memory pressure during pipe allocation.","commonSituations":"Same as stdin pipe failures: fd leaks from leaked pi processes, low LimitNOFILE in systemd/containers, fork bombs or runaway session loops exhausting descriptors.","solutions":["Kill leaked pi subprocesses and audit session teardown so stopped sessions release their pipes.","Raise the nofile limit (`ulimit -n` or LimitNOFILE in systemd) and restart cc-connect.","Check the wrapped cause for EMFILE/ENFILE and count open fds per process to find the leak.","If it persists without resource pressure, verify no custom code calls cmd.Start()/Wait() on the same exec.Cmd before startRPC finishes wiring pipes."],"exampleFix":"// before: sessions never stopped, fds leak\n// after: ensure teardown\nfunc (e *Engine) shutdown() {\n    for _, s := range e.sessions {\n        _ = s.Stop() // closes rpc pipes, reaps pi process\n    }\n}","handlingStrategy":"retry","validationCode":"var lim syscall.Rlimit\nsyscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)\nnFds, _ := countOpenFds(os.Getpid())\nif nFds > int(float64(lim.Cur)*0.8) {\n    return fmt.Errorf(\"fd usage %d/%d too high; restart daemon or raise limit before starting pi\", nFds, lim.Cur)\n}","typeGuard":null,"tryCatchPattern":"sess, err := agent.StartSession(ctx, opts)\nif err != nil && strings.Contains(err.Error(), \"stdout pipe\") {\n    log.Printf(\"stdout pipe allocation failed; likely fd exhaustion — check ulimit -n and leaked processes\")\n    return fmt.Errorf(\"resource exhaustion starting pi: %w\", err)\n}","preventionTips":["Raise LimitNOFILE/ulimit -n for the cc-connect service.","Ensure every started pi session is eventually Stop()'d so its pipes are released.","Alert on fd-count trends; treat 80% of the limit as a warning threshold.","Restart the daemon as a stopgap if descriptors leak, then fix the underlying leak."],"tags":["go","process-spawn","file-descriptors","pipe"],"backgroundTag":"file-descriptor-exhaustion","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}