{"record":{"id":"d732f72354b2da83","repo":"jdx/mise","slug":"agent-name-must-set-program","errorCode":null,"errorMessage":"agent '{name}' must set `program`","messagePattern":"agent '(.+?)' must set `program`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/launchd.rs","lineNumber":115,"sourceCode":"    Differs,\n    Missing,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub(crate) struct LaunchdStatus {\n    pub request: LaunchdRequest,\n    pub path: PathBuf,\n    pub loaded: bool,\n    pub state: LaunchdState,\n}\n\nimpl LaunchdRequest {\n    pub(crate) fn from_toml(name: String, config: LaunchdTomlConfig) -> Result<Self> {\n        if !valid_name(&name) {\n            bail!(\"agent name '{name}' must contain only letters, numbers, '.', '_', or '-'\");\n        }\n        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 config.keep_alive && config.keep_alive_on_failure {\n            bail!(\"agent '{name}' cannot set both `keep_alive` and `keep_alive_on_failure`\");\n        }\n        if config.nice.is_some_and(|nice| !(-20..=20).contains(&nice)) {\n            bail!(\"agent '{name}' `nice` must be between -20 and 20\");\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","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/launchd.rs#L97-L133","documentation":"LaunchdRequest::from_toml requires every launchd agent to define a `program` field, since launchd needs a command to run. If LaunchdTomlConfig.program is None (missing from the TOML), the function bails with this message. It is a missing-required-field check at config parse time.","triggerScenarios":"Defining an [agent.NAME] section without a `program` key, or programmatically constructing LaunchdTomlConfig with program = None.","commonSituations":"Creating an empty agent stub and forgetting to fill in program; commenting out the program line while keeping the agent section; copying an agent config that relies on a key another version supported.","solutions":["Add a `program` key to the agent config pointing at the executable to run","Remove the agent section if it is not needed","Verify the TOML section is not shadowed so `program` actually lands in the intended agent"],"exampleFix":"# before\n[agent.backup]\nkeep_alive = true\n# after\n[agent.backup]\nprogram = \"/usr/local/bin/backup.sh\"\nkeep_alive = true","handlingStrategy":"validation","validationCode":"if \"program\" not in agent_cfg:\n    raise ValueError(f\"agent '{name}' needs a program\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair every agent section with a program key","Use a config schema requiring `program`","Review commented-out program lines when editing agent configs"],"tags":["launchd","config","missing-field"],"backgroundTag":"missing-required-config-field","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}