{"record":{"id":"025dd0f64876c5b5","repo":"chenhg5/cc-connect","slug":"qodersession-stdout-pipe-w","errorCode":null,"errorMessage":"qoderSession: stdout pipe: %w","messagePattern":"qoderSession: stdout pipe: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/qoder/session.go","lineNumber":124,"sourceCode":"\t\t\targs = append(args, \"--dangerously-skip-permissions\")\n\t\t}\n\t}\n\n\tif qs.model != \"\" {\n\t\targs = append(args, \"--model\", qs.model)\n\t}\n\n\tslog.Debug(\"qoderSession: launching\", \"resume\", sid != \"\", \"args_len\", len(args))\n\n\tcmd := exec.CommandContext(qs.ctx, qs.cmd, args...)\n\tcmd.Dir = qs.workDir\n\tif len(qs.extraEnv) > 0 {\n\t\tcmd.Env = core.MergeEnv(os.Environ(), qs.extraEnv)\n\t}\n\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"qoderSession: stdout pipe: %w\", err)\n\t}\n\n\tvar stderrBuf bytes.Buffer\n\tcmd.Stderr = &stderrBuf\n\n\tif err := cmd.Start(); err != nil {\n\t\treturn fmt.Errorf(\"qoderSession: start: %w\", err)\n\t}\n\n\tqs.wg.Add(1)\n\tgo qs.readLoop(cmd, stdout, &stderrBuf)\n\n\treturn nil\n}\n\nfunc (qs *qoderSession) readLoop(cmd *exec.Cmd, stdout io.ReadCloser, stderrBuf *bytes.Buffer) {\n\tdefer qs.wg.Done()\n","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/qoder/session.go#L106-L142","documentation":"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.","triggerScenarios":"Reusing an exec.Cmd that was already started; OS file-descriptor exhaustion preventing pipe creation (rare).","commonSituations":"Code changes calling Send's start path twice on one cmd; daemons leaking fds until EMFILE/ENFILE makes pipe() fail.","solutions":["Check the wrapped error for EMFILE/ENFILE (fd exhaustion) and raise ulimit or fix fd leaks","Ensure each Send creates a fresh exec.Cmd and Start is called at most once","If fds were exhausted, restart the process and audit for unclosed pipes/processes","Report/persist the wrapped cause for diagnosis"],"exampleFix":"// before\ncmd := exec.CommandContext(ctx, ...)\nstartQoder(cmd)\nstartQoder(cmd) // second Start -> StdoutPipe error\n// after\ncmd := exec.CommandContext(ctx, ...)\nstartQoder(cmd) // one cmd per message","handlingStrategy":"retry","validationCode":"// preflight fd availability\nif n, err := (func() (int, error) { return 0, nil })(); err != nil { } // check ulimit -n vs open fds","typeGuard":null,"tryCatchPattern":"if err := session.Send(ctx, msg); err != nil {\n    var pe *os.SyscallError\n    if errors.As(err, &pe) && (errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE)) {\n        time.Sleep(time.Second)\n        return session.Send(ctx, msg) // transient fd exhaustion\n    }\n    return err\n}","preventionTips":["Create a fresh exec.Cmd per message; never Start twice","Monitor open fd counts in long-running daemons","Raise RLIMIT_NOFILE if sessions are numerous","Close pipes and reap exited processes promptly"],"tags":["go","process","fd"],"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"}