{"record":{"id":"038812bb21627189","repo":"chenhg5/cc-connect","slug":"codex-app-server-stdin-pipe-w","errorCode":null,"errorMessage":"codex app-server stdin pipe: %w","messagePattern":"codex app-server stdin pipe: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/codex/appserver_session.go","lineNumber":266,"sourceCode":"\tif provider := strings.TrimSpace(s.modelProvider); provider != \"\" {\n\t\targs = append(args, \"-c\", fmt.Sprintf(\"model_provider=%q\", provider))\n\t}\n\tif baseURL := strings.TrimSpace(s.baseURL); baseURL != \"\" {\n\t\targs = append(args, \"-c\", fmt.Sprintf(\"openai_base_url=%q\", baseURL))\n\t}\n\tcmd := exec.CommandContext(s.ctx, \"codex\", args...)\n\tcmd.Dir = s.workDir\n\tenv := append([]string(nil), s.extraEnv...)\n\tif s.codexHome != \"\" {\n\t\tenv = append(env, \"CODEX_HOME=\"+s.codexHome)\n\t}\n\tif len(env) > 0 {\n\t\tcmd.Env = core.MergeEnv(os.Environ(), env)\n\t}\n\n\tstdin, err := cmd.StdinPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"codex app-server stdin pipe: %w\", err)\n\t}\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"codex app-server stdout pipe: %w\", err)\n\t}\n\tstderr, err := cmd.StderrPipe()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"codex app-server stderr pipe: %w\", err)\n\t}\n\tif err := cmd.Start(); err != nil {\n\t\treturn fmt.Errorf(\"codex app-server start: %w\", err)\n\t}\n\n\ts.procMu.Lock()\n\ts.cmd = cmd\n\ts.stdin = stdin\n\ts.procMu.Unlock()\n","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/codex/appserver_session.go#L248-L284","documentation":"This error wraps a failure from cmd.StdinPipe() while starting the codex app-server child process. Obtaining the stdin pipe is part of the child-process bootstrap in the codex agent session; if the OS refuses to allocate the pipe (rare, usually fd exhaustion), the session cannot send JSON-RPC requests to the app-server. The library wraps the OS error with context so callers know which pipe stage failed.","triggerScenarios":"Calling StartSession/ensureStarted on the codex agent, which executes the appServerSession process-startup path; cmd.StdinPipe() returns a non-nil error — almost always because the process has exhausted its file-descriptor limit (EMFILE/ENFILE).","commonSituations":"ulimit -n too low on a host running many sessions; file-descriptor leak in a long-running daemon accumulating child processes; container with a low RLIMIT_NOFILE.","solutions":["Raise the file-descriptor limit (ulimit -n 4096 or systemd LimitNOFILE=4096) for the cc-connect process.","Check for fd leaks: lsof -p <pid> | wc -l; ensure closed sessions release pipes.","Restart the daemon to release leaked descriptors as an immediate mitigation."],"exampleFix":"// before\nstdin, err := cmd.StdinPipe()\nif err != nil {\n    return fmt.Errorf(\"codex app-server stdin pipe: %w\", err)\n}\n// after\n// no code change possible to fix EMFILE; ensure enclosing startup retries\n// after caller raises RLIMIT_NOFILE:\nif err := start(); err != nil && errors.Is(err, syscall.EMFILE) {\n    return fmt.Errorf(\"file descriptor limit reached; raise RLIMIT_NOFILE: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check fd headroom before spawning the app-server\nvar lim syscall.Rlimit\nsyscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)\nopenFDs := countOpenFDs() // e.g. via /proc/self/fd\nif openFDs > int(lim.Cur)-64 {\n    return errors.New(\"file descriptor limit nearly exhausted; raise RLIMIT_NOFILE\")\n}","typeGuard":null,"tryCatchPattern":"if err := session.Start(ctx); err != nil {\n    var syscallErr *os.SyscallError\n    if errors.As(err, &syscallErr) && (errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE)) {\n        return fmt.Errorf(\"fd limit reached; raise RLIMIT_NOFILE: %w\", err)\n    }\n    return err\n}","preventionTips":["Raise RLIMIT_NOFILE (ulimit -n / systemd LimitNOFILE) for long-running daemons.","Close sessions deterministically so pipes are released.","Monitor open fd counts and alert before exhaustion.","Restart daemons on a schedule if fd growth is expected."],"tags":["go","process","file-descriptors","pipe"],"backgroundTag":"file-descriptor-exhausted","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"}