{"record":{"id":"578b1253a1233c7f","repo":"jdx/mise","slug":"hook-command-failed-status","errorCode":null,"errorMessage":"hook command failed: {status}","messagePattern":"hook command failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/hooks.rs","lineNumber":775,"sourceCode":"            let mut c = std::process::Command::new(&shell[0]);\n            for a in &cmd_args {\n                c.raw_arg(a);\n            }\n            c.env_clear();\n            c.envs(env.iter());\n            if matches!(hook.hook, Hooks::Preinstall | Hooks::Postinstall) {\n                c.current_dir(project_root);\n            }\n            // Send the hook's stdout to mise's stderr (matching the duct\n            // `stdout_to_stderr()` the non-cmd path uses) by handing the child a\n            // clone of our stderr handle. Redirecting the descriptor directly —\n            // rather than piping through a reader thread — means a hook that\n            // spawns a background child holding the write end can't block us\n            // waiting for pipe EOF, and stdout/stderr ordering is preserved.\n            c.stdout(std::io::stderr().as_handle().try_clone_to_owned()?);\n            let status = c.status()?;\n            if !status.success() {\n                eyre::bail!(\"hook command failed: {status}\");\n            }\n            return Ok(());\n        }\n    }\n\n    let cwd = matches!(hook.hook, Hooks::Preinstall | Hooks::Postinstall).then_some(project_root);\n    let mut command = cmd(&shell[0], args).full_env(&env);\n    if let Some(cwd) = cwd {\n        command = command.dir(cwd);\n    }\n    crate::inline_command::optimize_expression(command, run, &env, cwd, direct_enabled)\n        .stdout_to_stderr()\n        .run()?;\n    Ok(())\n}\n\nasync fn execute_task(\n    config: &Arc<Config>,","sourceCodeStart":757,"sourceCodeEnd":793,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/hooks.rs#L757-L793","documentation":"mise hooks (pre/post install, activate, etc.) execute a user-defined command and require a zero exit status. When the hook's child process exits non-zero, execute wraps the exit status in this error, propagating the hook failure to the caller (run_matched_hook).","triggerScenarios":"A hook configured in mise.toml ([hooks] preinstall/postinstall or a plugin hook) runs a command that exits non-zero; the command is missing, crashes, or its script returns failure.","commonSituations":"postinstall script referencing a tool not yet installed (PATH issues); hook script with a syntax error or missing executable bit; hook relies on env vars not present at hook time; project scripts failing during a shared `mise install`.","solutions":["Run the hook command manually in the project root to see its actual output/error and fix the script","Check that the command exists on PATH at the time hooks run (mise shims vs system PATH)","Fix the hook script so it exits 0 on success paths; guard optional steps so they don't fail the install","Temporarily comment out the hook in mise.toml to unblock the main operation, fix, then re-enable"],"exampleFix":"// before (mise.toml)\n[hooks]\npostinstall = \"./scripts/setup.sh --strict\"  # exits 1 when optional deps missing\n// after\n[hooks]\npostinstall = \"./scripts/setup.sh || echo 'setup skipped'\"","handlingStrategy":"try-catch","validationCode":"// verify the hook command exists before running\nlet status = std::process::Command::new(\"sh\").arg(\"-c\").arg(&hook_cmd)\n    .status()?;\nassert!(status.success(), \"hook would fail: {hook_cmd}\");","typeGuard":null,"tryCatchPattern":"if let Err(e) = run_matched_hook(&hook, ...) {\n    eprintln!(\"hook {} failed: {e:#}; continuing or aborting per policy\", hook.name());\n    // decide: abort the install, or log and continue\n}","preventionTips":["Test hook scripts manually in a clean shell mimicking mise's PATH","Make hooks idempotent and tolerant of missing optional tools","Keep hooks minimal; move complex logic into robust project scripts"],"tags":["hooks","process","exit-status"],"backgroundTag":"command-not-found","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"}