{"record":{"id":"0cfc06595afa49d7","repo":"chenhg5/cc-connect","slug":"copilotsession-stdout-pipe-w","errorCode":null,"errorMessage":"copilotSession: stdout pipe: %w","messagePattern":"copilotSession: stdout pipe: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/copilot/session.go","lineNumber":115,"sourceCode":"\tchild.Dir = workDir\n\tprepareCmdForKill(child)\n\n\tenv := os.Environ()\n\tif len(extraEnv) > 0 {\n\t\tenv = core.MergeEnv(env, extraEnv)\n\t}\n\tchild.Env = env\n\n\tstdin, err := child.StdinPipe()\n\tif err != nil {\n\t\tcancel()\n\t\treturn nil, fmt.Errorf(\"copilotSession: stdin pipe: %w\", err)\n\t}\n\n\tstdout, err := child.StdoutPipe()\n\tif err != nil {\n\t\tcancel()\n\t\treturn nil, fmt.Errorf(\"copilotSession: stdout pipe: %w\", err)\n\t}\n\n\tvar stderrBuf bytes.Buffer\n\tchild.Stderr = &stderrBuf\n\n\tif err := child.Start(); err != nil {\n\t\tcancel()\n\t\treturn nil, fmt.Errorf(\"copilotSession: start: %w\", err)\n\t}\n\n\tcs := &copilotSession{\n\t\tcmd:                child,\n\t\trpc:                newRPCClient(stdin),\n\t\treader:             newLSPReader(stdout),\n\t\tevents:             make(chan core.Event, 64),\n\t\tmode:               mode,\n\t\tmodel:              model,\n\t\tprovider:           provider,","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/copilot/session.go#L97-L133","documentation":"Right after acquiring the stdin pipe, newCopilotSession calls child.StdoutPipe() to receive the copilot CLI's JSON-RPC responses. On failure the context is cancelled and the error is wrapped as \"copilotSession: stdout pipe: %w\". Like the stdin variant, it indicates the OS refused to create the pipe, so session setup cannot continue.","triggerScenarios":"StartSession → newCopilotSession where StdoutPipe() fails — fd exhaustion, an exec.Cmd that has already been started/Waited, or OS pipe limits hit.","commonSituations":"Long-running daemon leaking pipes from earlier sessions; low fd limits in constrained environments; accidental double-start of the same exec.Cmd.","solutions":["Audit session lifecycle for leaked pipes (Close()/Wait on finished sessions) and fix the leak","Raise the fd limit (ulimit -n / systemd LimitNOFILE) for the daemon","Always construct a new exec.Cmd per session instead of reusing one","Restart the process if fds are exhausted; then verify the leak is fixed under load"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"sess, err := StartSession(ctx, cfg, resumeID)\nif err != nil {\n    if strings.Contains(err.Error(), \"stdout pipe\") {\n        slog.Error(\"copilot: cannot create stdout pipe (fd exhaustion?)\", \"err\", err)\n    }\n    return fmt.Errorf(\"start session: %w\", err)\n}","preventionTips":["Same fd-hygiene as stdin pipes: close sessions deterministically","Use sync.Once/defer for teardown so pipes never leak on error paths","Set generous fd limits for the daemon user","Load-test session churn to expose leaks"],"tags":["process","pipe","stdout","exec"],"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"}