jdx/mise · error
agent ' ' `queue_directories` entry ' ' must be an absolute…
Error message
agent '{name}' `queue_directories` entry '{dir}' must be an absolute path (launchd requires absolute paths; `~` and `~/` are expanded) What it means
launchd requires queue directory watch paths to be absolute POSIX paths; the plist is consumed by macOS launchd regardless of which platform parses the config. LaunchdRequest::from_toml checks each queue_directories entry with is_absolute_launchd_path() against the raw string and bails with this message for relative paths, explaining that `~` and `~/` prefixes are expanded. On Windows, Path::is_absolute would wrongly reject root-relative POSIX paths, hence the custom check.
Solutions
- Prefix the entry with '/' to make it an absolute POSIX path
- Use '~/...' paths, which are expanded to the user's home directory
- On Windows-authored configs, still write POSIX-style paths since launchd runs on macOS
Example fix
# before queue_directories = ["spool/mail"] # after queue_directories = ["/var/spool/mail"]
Defensive patterns
Strategy: validation
Validate before calling
import os
for d in agent_cfg.get("queue_directories", []):
assert d.startswith(("/", "~/")) or d == "~", f"'{d}' must be absolute or ~-prefixed" Prevention
- Always write launchd paths as absolute POSIX paths
- Use ~/ for home-relative directories
- Never use Windows-style paths in launchd agent configs
When it happens
Trigger: A queue_directories entry like "spool/mail" or "./data" that is neither absolute, nor `~`/`~/`-prefixed, and cannot be expanded to an absolute path.
Common situations: Writing relative paths assuming they resolve relative to the config file; using Windows-style absolute paths ('C:\\data') in a launchd plist; forgetting the leading '/' or '~'.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- agent ' ' `start_calendar_interval. ` must be between and
- agent ' ' `start_calendar_interval` must set at least one…
- agent ' ' `start_calendar_interval` must not be empty
- agent ' ' cannot set both `keep_alive` and…
- agent ' ' must set a non-empty `program
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/a6d8dd21a0d30c9d.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/launchd.rs:138
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 \
(launchd requires absolute paths; `~` and `~/` are expanded)"
);
}
}
Ok(Self {
label: format!("dev.mise.{name}"),
name,
program,
args: config.args,
run_at_load: config.run_at_load,
keep_alive: config.keep_alive,
keep_alive_on_failure: config.keep_alive_on_failure,
start_interval: config.start_interval,
throttle_interval: config.throttle_interval,
nice: config.nice,
start_calendar_interval: config.start_calendar_interval,
queue_directories: config.queue_directories,View on GitHub (pinned to 533346cc37)