{"record":{"id":"8e0462552a331881","repo":"sinelaw/fresh","slug":"failed-to-spawn-shell","errorCode":null,"errorMessage":"Failed to spawn shell: {}","messagePattern":"Failed to spawn shell: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/fresh-editor/src/app/shell_command.rs","lineNumber":268,"sourceCode":"    pub(crate) fn run_shell_command_blocking(&mut self, command: &str) -> anyhow::Result<()> {\n        use crossterm::terminal::{\n            disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,\n        };\n        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())","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-editor/src/app/shell_command.rs#L250-L286","documentation":"run_shell_command_blocking pauses the TUI and spawns the user's default shell (detect_shell) with `sh -c <command>` to run a shell command synchronously. If Command::spawn fails — shell binary missing, not executable, or OS resource limits — this error reports the underlying io::Error.","triggerScenarios":"detect_shell() resolves to a binary that doesn't exist or isn't executable (bad $SHELL, minimal container without bash); fork/exec fails due to process/file-descriptor limits; PATH lacks the shell.","commonSituations":"Running the editor inside minimal Docker images lacking a shell; $SHELL pointing to a removed binary; sandboxed environments (flatpak/nix) where the shell isn't on PATH; ulimit restrictions.","solutions":["Check the wrapped io::Error in the message (NotFound => shell missing, PermissionDenied => chmod +x or pick another shell)","Verify the shell resolved by detect_shell() exists: echo $SHELL and which <shell>","Set $SHELL to an existing shell or install one in the environment/container","Add a fallback in detect_shell() to /bin/sh when the detected shell cannot be spawned"],"exampleFix":"// before\nlet shell = detect_shell();\nlet mut child = Command::new(&shell).args([\"-c\", command]).hide_window().spawn()\n    .map_err(|e| anyhow::anyhow!(\"Failed to spawn shell: {}\", e))?;\n// after\nlet shell = detect_shell();\nlet mut child = Command::new(&shell).args([\"-c\", command]).hide_window().spawn()\n    .map_err(|e| anyhow::anyhow!(\"Failed to spawn shell '{}': {} (check $SHELL and PATH)\", shell.display(), e))?;","handlingStrategy":"validation","validationCode":"let shell = std::env::var(\"SHELL\").unwrap_or_else(|_| \"/bin/sh\".into());\nif which::which(&shell).is_err() {\n    // fall back to /bin/sh before invoking the command\n}","typeGuard":null,"tryCatchPattern":"match run_shell_command_blocking(cmd) {\n    Err(e) if e.to_string().starts_with(\"Failed to spawn shell\") => {\n        show_error(format!(\"{e}; check $SHELL exists and is executable\"));\n    }\n    other => other?,\n}","preventionTips":["Keep a shell installed and on PATH in every environment the editor runs in (including containers)","Set $SHELL correctly; prefer /bin/sh fallbacks in minimal images","Watch for ENOENT vs EACCES in the wrapped io::Error to distinguish missing vs non-executable","Test shell integration in sandboxed/minimal environments before rollout"],"tags":["shell","process-spawn","environment"],"backgroundTag":"command-not-found","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}