jdx/mise · error
agent '{name}' cannot set both `keep_alive` and `keep_alive_
Error message
agent '{name}' cannot set both `keep_alive` and `keep_alive_on_failure` What it means
launchd agents support either keep_alive (restart always) or keep_alive_on_failure (restart only on non-zero exit), but not both simultaneously, since their semantics conflict. from_toml enforces this mutual exclusion when parsing the agent config. The user must pick one keep-alive strategy.
Source
Thrown at src/system/launchd.rs:121
pub request: LaunchdRequest,
pub path: PathBuf,
pub loaded: bool,
pub state: LaunchdState,
}
impl LaunchdRequest {
pub(crate) fn from_toml(name: String, config: LaunchdTomlConfig) -> Result<Self> {
if !valid_name(&name) {
bail!("agent name '{name}' must contain only letters, numbers, '.', '_', or '-'");
}
let Some(program) = config.program.map(|s| s.trim().to_string()) else {
bail!("agent '{name}' must set `program`");
};
if program.is_empty() {
bail!("agent '{name}' must set a non-empty `program`");
}
if config.keep_alive && config.keep_alive_on_failure {
bail!("agent '{name}' cannot set both `keep_alive` and `keep_alive_on_failure`");
}
if config.nice.is_some_and(|nice| !(-20..=20).contains(&nice)) {
bail!("agent '{name}' `nice` must be between -20 and 20");
}
if let Some(interval) = &config.start_calendar_interval {
interval.validate(&name)?;
}
for dir in &config.queue_directories {
if dir.trim().is_empty() {
bail!("agent '{name}' `queue_directories` must not contain empty entries");
}
// checked against the raw string rather than `Path::is_absolute` on the
// expanded value: the plist is consumed by macOS launchd, so POSIX rules
// apply regardless of the platform parsing the config, and on Windows
// `Path::new("/var/spool").is_absolute()` is false (root, but no prefix)
if !is_absolute_launchd_path(dir) {
bail!(
"agent '{name}' `queue_directories` entry '{dir}' must be an absolute path \View on GitHub (pinned to afd2eddd3a)
Solutions
- Keep only keep_alive = true if the agent should always be running
- Keep only keep_alive_on_failure = true if the agent should restart solely after failures
- Remove the boolean you do not want from the agent's TOML section
Example fix
// before [launchd.my-agent] keep_alive = true keep_alive_on_failure = true // after [launchd.my-agent] keep_alive_on_failure = true
Defensive patterns
Strategy: validation
Validate before calling
let keep_alive = cfg.get("keep_alive").and_then(|v| v.as_bool()).unwrap_or(false);
let on_failure = cfg.get("keep_alive_on_failure").and_then(|v| v.as_bool()).unwrap_or(false);
if keep_alive && on_failure {
anyhow::bail!("choose either keep_alive or keep_alive_on_failure, not both");
} Prevention
- Pick one restart policy per agent and document it
- When merging configs, drop one of the two keys explicitly
- Default to keep_alive_on_failure for crash-only services
When it happens
Trigger: Setting both keep_alive = true and keep_alive_on_failure = true on the same [launchd.<name>] agent section.
Common situations: Merging two agent configs (one using each option) during refactoring; copy-pasting keep_alive from an example while also enabling keep_alive_on_failure for crash-only restarts; experimenting with both restart modes.
Related errors
- agent '{name}' must set `program`
- agent '{name}' must set a non-empty `program`
- agent '{name}' `queue_directories` must not contain empty en
- Invalid checksum format: {}
- {option}: '{name}' must be a plain file name (no path separa
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/6c2d911fcc340057.
Report an issue: GitHub.