{"record":{"id":"a6d8dd21a0d30c9d","repo":"jdx/mise","slug":"agent-name-queue-directories-entry-dir-m","errorCode":null,"errorMessage":"agent '{name}' `queue_directories` entry '{dir}' must be an absolute path (launchd requires absolute paths; `~` and `~/` are expanded)","messagePattern":"agent '(.+?)' `queue_directories` entry '(.+?)' must be an absolute path \\(launchd requires absolute paths; `~` and `~/` are expanded\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/launchd.rs","lineNumber":124,"sourceCode":"        let Some(program) = config.program.map(|s| s.trim().to_string()) else {\n            bail!(\"agent '{name}' must set `program`\");\n        };\n        if program.is_empty() {\n            bail!(\"agent '{name}' must set a non-empty `program`\");\n        }\n        if let Some(interval) = &config.start_calendar_interval {\n            interval.validate(&name)?;\n        }\n        for dir in &config.queue_directories {\n            if dir.trim().is_empty() {\n                bail!(\"agent '{name}' `queue_directories` must not contain empty entries\");\n            }\n            // checked against the raw string rather than `Path::is_absolute` on the\n            // expanded value: the plist is consumed by macOS launchd, so POSIX rules\n            // apply regardless of the platform parsing the config, and on Windows\n            // `Path::new(\"/var/spool\").is_absolute()` is false (root, but no prefix)\n            if !is_absolute_launchd_path(dir) {\n                bail!(\n                    \"agent '{name}' `queue_directories` entry '{dir}' must be an absolute path \\\n                     (launchd requires absolute paths; `~` and `~/` are expanded)\"\n                );\n            }\n        }\n        Ok(Self {\n            label: format!(\"dev.mise.{name}\"),\n            name,\n            program,\n            args: config.args,\n            run_at_load: config.run_at_load,\n            keep_alive: config.keep_alive,\n            start_interval: config.start_interval,\n            throttle_interval: config.throttle_interval,\n            start_calendar_interval: config.start_calendar_interval,\n            queue_directories: config.queue_directories,\n            environment: config.environment,\n            working_directory: config.working_directory,","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/launchd.rs#L106-L142","documentation":"launchd demands absolute paths, so every queue_directories entry is checked by is_absolute_launchd_path: it must be exactly \"~\", start with \"~/\", or start with '/'. Relative paths (\"spool/mail\") and tilde-username paths (\"~user/spool\") are rejected — the latter deliberately, because mise only expands a leading \"~/\" and would otherwise hand launchd a literal '~user' path. Checked on the raw string so POSIX rules apply even when parsing on Windows.","triggerScenarios":"Writing queue_directories = [\"spool/mail\"] (relative), [\"~user/Mail\"] (tilde-username), or [\"./queue\"] in a [bootstrap.macos.launchd.agents.<name>] table.","commonSituations":"Paths written relative to the config file out of habit; '~' expansion assumptions carried from shell usage; configs authored on non-mac systems where the path shape was never exercised by launchd.","solutions":["Prefix the path with '/' (e.g. /var/spool/mail) or use '~/' for the home directory","Do not use '~user/' forms; expand the target user's home to an absolute path manually","Re-run mise bootstrap and confirm the agent validates"],"exampleFix":"# before\n[bootstrap.macos.launchd.agents.mailwatch]\nqueue_directories = [\"spool/mail\"]\n\n# after\n[bootstrap.macos.launchd.agents.mailwatch]\nqueue_directories = [\"/var/spool/mail\"]","handlingStrategy":"validation","validationCode":"python3 - <<'EOF'\nimport tomllib,sys\nc=tomllib.load(open('mise.toml','rb'))\ndef ok(p): return p=='~' or p.startswith('~/') or p.startswith('/')\nfor name,agent in (c.get('bootstrap',{}).get('macos',{}).get('launchd',{}).get('agents',{}) or {}).items():\n    for d in agent.get('queue_directories',[]) or []:\n        if not ok(d): sys.exit(f'agent {name}: queue path {d!r} must be absolute, ~, or ~/...')\nEOF","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always write absolute paths (or ~/) for launchd-managed directories","Do not use ~user forms — mise does not expand tilde-usernames here","Author macOS agent config on macOS and verify with launchctl after bootstrap"],"tags":["mise","macos","launchd","path-validation","bootstrap"],"backgroundTag":"relative-path-requires-absolute","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}