jdx/mise · error
agent '{name}' must set `program`
Error message
agent '{name}' must set `program` What it means
LaunchdRequest::from_toml requires every agent in [bootstrap.macos.launchd.agents] to declare a program key — the executable launchd will run. This error fires when the agent table exists without a program key at all; the value is trimmed before checks, and a present-but-empty value is a separate error. The agent is then skipped (logged as a warning).
Source
Thrown at src/system/launchd.rs:107
Differs,
Missing,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LaunchdStatus {
pub request: LaunchdRequest,
pub path: PathBuf,
pub loaded: bool,
pub state: LaunchdState,
}
impl LaunchdRequest {
pub 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 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 9dcfcaa0dc)
Solutions
- Add program = "/absolute/path/to/binary" to the agent table
- Check the key is spelled exactly `program` (not cmd/exec/command)
- Re-run mise bootstrap and confirm the agent appears in the plan
Example fix
# before [bootstrap.macos.launchd.agents.sync] args = ["--daemon"] # after [bootstrap.macos.launchd.agents.sync] program = "/usr/local/bin/sync" args = ["--daemon"]
Defensive patterns
Strategy: validation
Validate before calling
python3 - <<'EOF'
import tomllib,sys
c=tomllib.load(open('mise.toml','rb'))
for name,agent in (c.get('bootstrap',{}).get('macos',{}).get('launchd',{}).get('agents',{}) or {}).items():
if not isinstance(agent,dict) or 'program' not in agent: sys.exit(f'agent {name} missing program')
EOF Prevention
- Start every agent definition with program; add other keys afterwards
- Use the exact key `program`, not cmd/exec/command
- Watch bootstrap output warnings — invalid agents are skipped, not failed, so they can slip through silently
When it happens
Trigger: Writing an agent table that defines args/keep_alive/queue_directories but omits program, e.g. [bootstrap.macos.launchd.agents.worker] with only run_at_load = true.
Common situations: Assuming launchd infers the program from the agent name or an args list; incremental edits where program is commented out; YAML-to-TOML migration dropping the key.
Related errors
- agent name '{name}' must contain only letters, numbers, '.',
- 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
- expected a `run` command
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/d732f72354b2da83.
Report an issue: GitHub.