{"record":{"id":"aa46159ea42be7f7","repo":"slimtoolkit/slim","slug":"cannot-create-pipe-for-app-s-stream-w","errorCode":null,"errorMessage":"cannot create pipe for app %s stream: %w","messagePattern":"cannot create pipe for app (.+?) stream: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/app/sensor/monitor/composite.go","lineNumber":362,"sourceCode":"}\n\n// Using simple io.MultiWriter(os.Stdout, os.File) would make cmd.Wait()\n// block until either the cmd's stdout is closed or the multi-writer is closed.\n// However, both are impossible. We need the Wait() to return much earlier\n// than the process termination (see pkg/monitors/ptrace logic), and multi-writer\n// cannot be closed at all. Hence, the pipe trick.\nfunc dupAppStdStream(artifactsDir string, w io.Writer, kind string) (*os.File, *os.File, error) {\n\tfilename := filepath.Join(artifactsDir, \"app_\"+kind+\".log\")\n\n\tf, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0o644)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"cannot open file %q to duplicate app's %s stream: %w\", filename, kind, err)\n\t}\n\n\tpr, pw, err := os.Pipe()\n\tif err != nil {\n\t\tf.Close()\n\t\treturn nil, nil, fmt.Errorf(\"cannot create pipe for app %s stream: %w\", kind, err)\n\t}\n\n\tgo func() {\n\t\tn, err := io.Copy(io.MultiWriter(w, f), pr)\n\t\tlog.Debugf(\"dupAppStdStream: io.Copy() finished; written=%d error=%v\", n, err)\n\t}()\n\n\treturn pw, f, nil\n}\n\nfunc closeAll(cs []io.Closer) {\n\tfor _, c := range cs {\n\t\terrutil.WarnOn(c.Close())\n\t}\n}\n","sourceCodeStart":344,"sourceCodeEnd":378,"githubUrl":"https://github.com/slimtoolkit/slim/blob/81940d17fa112cc678e32209214bcb2355cb3004/pkg/app/sensor/monitor/composite.go#L344-L378","documentation":"After opening the app's stream log file, dupAppStdStream creates an os.Pipe used to tee the app's output to both the live writer and the file. This error is returned when os.Pipe() fails, wrapping the OS error; the already-opened file is closed first.","triggerScenarios":"os.Pipe() failing during NewCompositeMonitor — practically only when the process has exhausted its file descriptor limit (EMFILE) or the kernel cannot allocate a pipe (ENFILE).","commonSituations":"Long-running hosts or leaked fds causing the process to hit RLIMIT_NOFILE; system-wide file table exhaustion under heavy load.","solutions":["Check fd usage (lsof / ls /proc/<pid>/fd) and raise RLIMIT_NOFILE (ulimit -n) for the sensor process.","Fix fd leaks in the surrounding application before starting the monitor.","Retry after system load decreases if ENFILE (system-wide table full) is reported."],"exampleFix":"// before (shell)\n./sensor\n// after (shell)\nulimit -n 65536 && ./sensor","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"mon, err := NewCompositeMonitor(cfg)\nif err != nil && strings.Contains(err.Error(), \"cannot create pipe\") {\n    // likely fd exhaustion; free descriptors and retry once\n    runtime.GC()\n    mon, err = NewCompositeMonitor(cfg)\n}","preventionTips":["Raise RLIMIT_NOFILE for the sensor process (ulimit -n 65536).","Audit for fd leaks (unclosed files/pipes) in the host application.","Avoid starting monitors on systems already at file-table capacity."],"tags":["filesystem","pipe","resource-limits"],"backgroundTag":"too-many-open-files","analyzedSha":"81940d17fa112cc678e32209214bcb2355cb3004","analyzedAt":"2026-08-31T23:06:12.682Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}