jdx/mise · error
hook command failed
Error message
hook command failed: {status} What it means
When executing a hook command (src/hooks.rs), mise runs the command synchronously and checks its exit status. If the hook's process exits non-zero, execution bails with 'hook command failed: {status}' reporting the exit code/signal.
Solutions
- Read the hook's own stderr/stdout just above the error — the hook's output explains the root cause; fix the hook script.
- Run the hook's command manually in the project root to reproduce and debug it outside mise.
- If the hook intentionally blocks (preinstall gate), resolve the condition it checks (e.g. required config, allowed versions) before retrying.
Example fix
// before (.mise.toml hook) [hooks.postinstall] run = "npm run setup --silent" # fails if 'setup' script missing // after [hooks.postinstall] run = "npm run setup --if-present --silent"
Defensive patterns
Strategy: try-catch
Validate before calling
command -v "$hook_cmd" >/dev/null 2>&1 && echo ok || echo "hook command not available"
Try / catch
if ! mise install; then echo "install failed at hook stage; inspect hook output above" mise cfg ls 2>/dev/null || cat mise.toml fi
Prevention
- Test hook commands manually in the project root before committing them
- Use --if-present style guards in package-manager scripts invoked by hooks
- Keep hooks idempotent and fail with clear messages
When it happens
Trigger: Any hook (e.g. preinstall/postinstall or configured hooks) whose shell command exits with a non-zero status during run_matched_hook's execution path.
Common situations: A postinstall script referencing a missing tool or bad path; a preinstall gate script intentionally failing to block an install; script bugs (syntax error, failed assertion) in hook commands; environment differences making a hook fail under mise but not in an interactive shell.
Related errors
- command exited with non-zero status
- command exited with non-zero status
- compose command failed with
- failed: exit code
- failed: exit code
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/578b1253a1233c7f.
Report an issue: GitHub.
Appendix: source
Thrown at src/hooks.rs:781
let mut c = std::process::Command::new(&shell[0]);
for a in &cmd_args {
c.raw_arg(a);
}
c.env_clear();
c.envs(env.iter());
if matches!(hook.hook, Hooks::Preinstall | Hooks::Postinstall) {
c.current_dir(project_root);
}
// Send the hook's stdout to mise's stderr (matching the duct
// `stdout_to_stderr()` the non-cmd path uses) by handing the child a
// clone of our stderr handle. Redirecting the descriptor directly —
// rather than piping through a reader thread — means a hook that
// spawns a background child holding the write end can't block us
// waiting for pipe EOF, and stdout/stderr ordering is preserved.
c.stdout(std::io::stderr().as_handle().try_clone_to_owned()?);
let status = c.status()?;
if !status.success() {
eyre::bail!("hook command failed: {status}");
}
return Ok(());
}
}
let cwd = matches!(hook.hook, Hooks::Preinstall | Hooks::Postinstall).then_some(project_root);
let mut command = cmd(&shell[0], args).full_env(&env);
if let Some(cwd) = cwd {
command = command.dir(cwd);
}
crate::inline_command::optimize_expression(command, run, &env, cwd, direct_enabled)
.stdout_to_stderr()
.run()?;
Ok(())
}
async fn execute_task(
config: &Arc<Config>,View on GitHub (pinned to 533346cc37)