{"record":{"id":"2a84cbfc4385d230","repo":"herdrdev/herdr","slug":"login-shell-shell-is-not-executable","errorCode":null,"errorMessage":"login shell {shell:?} is not executable","messagePattern":"login shell (.+?) is not executable","errorType":"error_code","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"src/pane.rs","lineNumber":1454,"sourceCode":"    }\n    #[cfg(unix)]\n    {\n        use std::os::unix::fs::PermissionsExt;\n        metadata.permissions().mode() & 0o111 != 0\n    }\n    #[cfg(not(unix))]\n    {\n        true\n    }\n}\n\nfn resolve_shell_for_login_mode(shell: &str) -> io::Result<String> {\n    if shell.contains(std::path::MAIN_SEPARATOR) {\n        let path = Path::new(shell);\n        return is_executable_file(path)\n            .then(|| shell.to_string())\n            .ok_or_else(|| {\n                io::Error::new(\n                    io::ErrorKind::NotFound,\n                    format!(\"login shell {shell:?} is not executable\"),\n                )\n            });\n    }\n\n    std::env::var_os(\"PATH\")\n        .and_then(|path| {\n            std::env::split_paths(&path)\n                .map(|dir| dir.join(shell))\n                .find(|candidate| is_executable_file(candidate))\n        })\n        .and_then(|path| path.into_os_string().into_string().ok())\n        .ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::NotFound,\n                format!(\"login shell {shell:?} was not found on PATH\"),\n            )","sourceCodeStart":1436,"sourceCodeEnd":1472,"githubUrl":"https://github.com/herdrdev/herdr/blob/f457cff4f2648eee85d176f8a41861241d4e8428/src/pane.rs#L1436-L1472","documentation":"Herdr validates the shell used for login-mode panes. When the configured shell string contains a path separator (e.g. /bin/zsh or C:\\bin\\bash.exe), it must point to an existing executable file, otherwise this NotFound error is returned. It is a configuration-validation error raised before spawning the pane.","triggerScenarios":"Calling pane creation/login-mode shell resolution with a shell value containing a path separator that either does not exist, is a directory, or lacks executable permission. On Unix this fails is_executable_file (missing x bit or ENOENT); on Windows it fails if the file is absent or not a valid executable.","commonSituations":"User's login shell from /etc/passwd or $SHELL points to a removed/renamed binary (e.g. a brew-installed fish upgraded paths), a shell set via config with a typo, or a path copied from another machine. Also Nix/store paths that were garbage-collected.","solutions":["Verify the path exists and is executable: ls -l /path/to/shell and run it directly","Fix the shell setting in your shell/SSH/passwd configuration to point to the real executable","If the binary moved (e.g. Homebrew), update to the new path or symlink the old location","As a last resort set an absolute path to /bin/sh or /bin/bash"],"exampleFix":"// before\nshell = \"/opt/homebrew/bin/fish-4.0\"   // removed by upgrade\n// after\nshell = \"/opt/homebrew/bin/fish\"","handlingStrategy":"validation","validationCode":"let shell_path = std::path::Path::new(shell);\nif shell.contains(std::path::MAIN_SEPARATOR)\n    && !(shell_path.is_file()\n        && is_executable(shell_path))\n{\n    return Err(format!(\"login shell {shell:?} is not executable\").into());\n}","typeGuard":null,"tryCatchPattern":"match resolve_shell_for_login_mode(shell) {\n    Ok(resolved) => { /* proceed */ }\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {\n        // fall back to a known-good shell or surface a config error\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Validate the configured shell path at settings-load time and warn early","Offer a fallback to /bin/sh or $SHELL when validation fails","Re-validate after OS/shell upgrades that can move binaries"],"tags":["shell","login","filesystem","configuration","executable-not-found"],"backgroundTag":"invalid-executable-path","analyzedSha":"f457cff4f2648eee85d176f8a41861241d4e8428","analyzedAt":"2026-08-28T15:41:09.197Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}