jdx/mise · error
`launchctl {}` failed: {}
Error message
`launchctl {}` failed: {} What it means
A `launchctl ...` subprocess spawned by mise's launchd backend (bootstrap, bootout, kickstart, enable/disable, etc.) exited with a non-zero status. The message embeds the exact joined argv and launchctl's trimmed stderr, so the launchd error text (e.g. 'Load failed: 5: Input/output error' or 'No such process') is the real diagnostic. Note the async `?` on `.output()` maps spawn/IO failures to a different error; this bail is specifically for a completed process with a failing exit status.
Source
Thrown at src/system/launchd.rs:513
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.await?;
Ok(output.success())
}
async fn launchctl(args: &[String]) -> Result<()> {
debug!("$ launchctl {}", shell_words::join(args));
let output = tokio::process::Command::new("launchctl")
.args(args)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.await?;
if !output.status.success() {
bail!(
"`launchctl {}` failed: {}",
shell_words::join(args),
String::from_utf8_lossy(&output.stderr).trim()
);
}
Ok(())
}
async fn bootout(domain: &str, path: &Path) -> Result<()> {
let args = [
"bootout".to_string(),
domain.to_string(),
path.to_string_lossy().to_string(),
];
match launchctl(&args).await {
Ok(()) => Ok(()),
Err(err) if bootout_missing_error(&err.to_string()) => Ok(()),
Err(err) => Err(err),View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Read the embedded launchctl stderr — it names the actual OS-level failure; fix that first
- Verify the domain and path: user agents need `gui/$(id -u)`, system daemons need `sudo` and the `system` domain
- Check the generated plist at ~/Library/LaunchAgents/dev.mise.<name>.plist (or /Library/LaunchDaemons) with `plutil -lint` and compare against the loaded version via `launchctl print`
- If the service is in a wedged state, run `launchctl bootout <domain> <plist-or-label>` manually once, then re-run mise
- Re-run with MISE_DEBUG=1 to see the exact `$ launchctl ...` line being executed
Example fix
# before: wrong domain for a LaunchAgent, launchctl exits non-zero launchctl bootstrap system ~/Library/LaunchAgents/dev.mise.backup.plist # after: bootstrap into the user's GUI domain launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/dev.mise.backup.plist
Defensive patterns
Strategy: retry
Validate before calling
# Pre-flight the operations mise will perform launchctl print "gui/$(id -u)/dev.mise.<name>" >/dev/null 2>&1 || echo "agent not loaded yet" plutil -lint ~/Library/LaunchAgents/dev.mise.<name>.plist # plist is valid
Try / catch
// Rust callers wrapping mise's system module: distinguish process failure from spawn failure
match launchctl(&args).await {
Ok(()) => {}
Err(report) if report.to_string().starts_with("`launchctl") => {
// completed with non-zero exit: stderr is embedded — surface it, consider one retry after bootout
eprintln!("launchctl rejected: {report}");
}
Err(e) => { /* spawn/IO failure — different remediation */ }
} Prevention
- Keep managed plists untouched; edit mise.toml and let mise regenerate them
- Use the right domain: gui/$(id -u) for agents, sudo + system domain for daemons
- When a service wedges, `launchctl bootout` manually once before re-running mise
- Run with MISE_DEBUG=1 to capture the exact failing launchctl invocation
When it happens
Trigger: Running `mise bootstrap apply` (or service status/sync flows) where mise executes e.g. `launchctl bootstrap gui/501 /Library/LaunchDaemons/dev.mise.x.plist` or `launchctl bootout gui/501 ...` and launchctl rejects it: malformed/generated plist, label mismatch, operation not permitted (daemon vs gui domain), service not currently loaded when kicking out, or SIP-protected locations.
Common situations: Editing a managed plist by hand so the on-disk copy diverges from what launchd loaded; targeting the wrong domain type (gui/<uid> vs system) for a daemon; running without sudo where LaunchDaemons require root; macOS changing bootstrap semantics across versions; a BootOut on an already-booted-out service on newer macOS which returns an error.
Related errors
- agent name '{name}' must contain only letters, numbers, '.',
- agent '{name}' must set `program`
- agent '{name}' must set a non-empty `program`
- agent '{name}' `queue_directories` must not contain empty en
- agent '{name}' `queue_directories` entry '{dir}' must be an
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/5efa25a78d86e0d4.
Report an issue: GitHub.