{"record":{"id":"b471b2ad8524186e","repo":"sinelaw/fresh","slug":"failed-to-wait-for-command","errorCode":null,"errorMessage":"Failed to wait for command: {}","messagePattern":"Failed to wait for command: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/src/app/shell_command.rs","lineNumber":272,"sourceCode":"        use crossterm::ExecutableCommand;\n        use std::io::stdout;\n\n        // Suspend TUI — best-effort, nothing useful to do on failure.\n        #[allow(clippy::let_underscore_must_use)]\n        let _ = disable_raw_mode();\n        #[allow(clippy::let_underscore_must_use)]\n        let _ = stdout().execute(LeaveAlternateScreen);\n\n        let shell = detect_shell();\n        let mut child = Command::new(&shell)\n            .args([\"-c\", command])\n            .hide_window()\n            .spawn()\n            .map_err(|e| anyhow::anyhow!(\"Failed to spawn shell: {}\", e))?;\n\n        let status = child\n            .wait()\n            .map_err(|e| anyhow::anyhow!(\"Failed to wait for command: {}\", e))?;\n\n        // Resume TUI — best-effort, nothing useful to do on failure.\n        #[allow(clippy::let_underscore_must_use)]\n        let _ = stdout().execute(EnterAlternateScreen);\n        #[allow(clippy::let_underscore_must_use)]\n        let _ = enable_raw_mode();\n\n        // Request a full hard redraw to clear any ghost text from the external command\n        self.request_full_redraw();\n\n        if status.success() {\n            Ok(())\n        } else {\n            anyhow::bail!(\"Command failed with exit code: {:?}\", status.code())\n        }\n    }\n}\n","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/src/app/shell_command.rs#L254-L290","documentation":"After spawning the shell, run_shell_command_blocking calls child.wait() to collect the exit status. Failure to wait (the child handle's stdin/stdout pipes are broken or the process data is unreadable) yields this error wrapping the io::Error; note this is not the same as the command exiting non-zero.","triggerScenarios":"child.wait() returns an io::Error — typically because the child process was reaped elsewhere, its pipes closed unexpectedly, or the process was killed in a way that invalidates the handle (SIGKILL of the process group, terminal teardown).","commonSituations":"User kills the shell's process group (Ctrl-C / kill -9) while a long command runs; terminal session drops over ssh mid-command; the process outlives the parent's ability to reap it.","solutions":["Check the wrapped io::Error; BrokenPipe/ECHILD usually means the child died externally — treat it as a non-fatal command failure","Re-run the command after restoring the terminal (the code re-enters the alternate screen afterward)","Avoid killing the editor's process group while a shell command is running","Consider using waitpid semantics/try_wait and reporting the exit status instead of erroring on reap failure"],"exampleFix":"// before\nlet status = child.wait()\n    .map_err(|e| anyhow::anyhow!(\"Failed to wait for command: {}\", e))?;\n// after\nlet status = child.wait().unwrap_or_else(|e| {\n    log::warn!(\"failed to reap shell command: {e}\");\n    std::process::exit_status_approximation::failure()\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// treat reap failure as a soft failure, not a fatal error\nlet status = match child.wait() {\n    Ok(s) => s,\n    Err(e) => {\n        log::warn!(\"could not reap shell command: {e}\");\n        return Ok(1); // assume failure exit code\n    }\n};","preventionTips":["Don't kill the editor's process group while a synchronous shell command runs","Keep the terminal session stable over ssh (use tmux/mosh for long commands)","Handle ECHILD/BrokenPipe as 'command died externally' rather than propagating a hard error","Always restore the TUI (alternate screen + raw mode) even when wait fails"],"tags":["shell","process","unix"],"backgroundTag":"process-wait-failed","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}