{"record":{"id":"c6dba2ce5504e0e8","repo":"jdx/mise","slug":"command-output-pipes-did-not-close-within-pipe-dr","errorCode":null,"errorMessage":"command output pipes did not close within {pipe_drain_timeout:?}","messagePattern":"command output pipes did not close within (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd.rs","lineNumber":1432,"sourceCode":"                        #[cfg(unix)]\n                        signal_process_tree(id, nix::sys::signal::Signal::SIGKILL);\n                        #[cfg(windows)]\n                        kill_process_tree(id);\n                        let _ = wait.await;\n                        return Err(err);\n                    }\n                }\n            }\n        }\n        let drain_deadline = Instant::now() + pipe_drain_timeout;\n        loop {\n            let remaining = drain_deadline.saturating_duration_since(Instant::now());\n            if remaining.is_zero() {\n                #[cfg(unix)]\n                signal_process_tree(id, nix::sys::signal::Signal::SIGKILL);\n                #[cfg(windows)]\n                kill_process_tree(id);\n                bail!(\"command output pipes did not close within {pipe_drain_timeout:?}\");\n            }\n            let output = match tokio::time::timeout(remaining, rx.recv()).await {\n                Ok(Some(output)) => output,\n                Ok(None) => break,\n                Err(_) => {\n                    #[cfg(unix)]\n                    signal_process_tree(id, nix::sys::signal::Signal::SIGKILL);\n                    #[cfg(windows)]\n                    kill_process_tree(id);\n                    bail!(\"command output pipes did not close within {pipe_drain_timeout:?}\");\n                }\n            };\n            if let Err(err) = consume(output) {\n                #[cfg(unix)]\n                signal_process_tree(id, nix::sys::signal::Signal::SIGKILL);\n                #[cfg(windows)]\n                kill_process_tree(id);\n                return Err(err);","sourceCodeStart":1414,"sourceCodeEnd":1450,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/cmd.rs#L1414-L1450","documentation":"After the child process exited, its output pipes did not close within pipe_drain_timeout — some descendant inherited the pipe and kept it open. mise waits until the drain deadline, then kills the whole process tree (SIGKILL on unix, kill_process_tree on Windows) and reports `command output pipes did not close within <duration>`.","triggerScenarios":"execute_hashes_async: the main child exited but rx never got EOF within pipe_drain_timeout because a grandchild/daemon holds stdout/stderr open; the deadline is reached and the tree is killed.","commonSituations":"Tasks that spawn background daemons/servers (dev servers, watchers) which inherit stdio; scripts launching nohup'd or detached grandchildren; test runners leaving orphaned child processes.","solutions":["Make the task's spawned background processes detach or close inherited stdio (e.g. `daemon >log 2>&1 </dev/null &`).","Don't leave dev servers/watchers running at the end of a task; kill them explicitly in the task script.","Increase pipe_drain_timeout if the remaining writers legitimately need more time.","Use setsid/nohup or redirect all three fds so the grandchild no longer holds the pipe."],"exampleFix":"// before (task script)\nnpm run dev &\nbuild && test\n# pipes never close; killed after drain timeout\n// after\nnohup npm run dev >server.log 2>&1 < /dev/null &\nbuild && test && kill $!","handlingStrategy":"validation","validationCode":"# ensure no descendants will hold the pipes open\nscript -c 'setsid bash -c \"your-daemon >log 2>&1 </dev/null &\"' /dev/null","typeGuard":null,"tryCatchPattern":"if mise run task 2>&1 | grep -q 'pipes did not close'; then kill_leftover_daemons; fi","preventionTips":["Redirect stdin/stdout/stderr of any backgrounded process to files or /dev/null.","Explicitly kill dev servers/watchers at the end of task scripts.","Never nohup background jobs without redirecting all three fds inside mise tasks."],"tags":["pipe","process-tree","timeout","async"],"backgroundTag":"broken-pipe","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}