{"record":{"id":"eff1e19779ed0424","repo":"jdx/mise","slug":"timer-unit-name-cannot-set-service-only-direct","errorCode":null,"errorMessage":"timer unit '{name}' cannot set service-only directive(s): {}","messagePattern":"timer unit '(.+?)' cannot set service-only directive\\(s\\): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/systemd.rs","lineNumber":202,"sourceCode":"                (config.timeout_start_sec.is_some(), \"timeout_start_sec\"),\n                (config.timeout_stop_sec.is_some(), \"timeout_stop_sec\"),\n                (config.no_new_privileges.is_some(), \"no_new_privileges\"),\n                (config.private_tmp.is_some(), \"private_tmp\"),\n                (!config.environment.is_empty(), \"environment\"),\n                (!config.environment_file.is_empty(), \"environment_file\"),\n                (config.nice.is_some(), \"nice\"),\n                (config.umask.is_some(), \"umask\"),\n                (config.working_directory.is_some(), \"working_directory\"),\n                (config.restart.is_some(), \"restart\"),\n                (config.restart_sec.is_some(), \"restart_sec\"),\n                (config.standard_output.is_some(), \"standard_output\"),\n                (config.standard_error.is_some(), \"standard_error\"),\n            ]\n            .into_iter()\n            .filter_map(|(is_set, field)| is_set.then_some(field))\n            .collect::<Vec<_>>();\n            if !service_only_fields.is_empty() {\n                bail!(\n                    \"timer unit '{name}' cannot set service-only directive(s): {}\",\n                    service_only_fields.join(\", \")\n                );\n            }\n            if config.on_boot_sec.is_none()\n                && config.on_unit_active_sec.is_none()\n                && config.on_unit_inactive_sec.is_none()\n                && config.on_calendar.is_none()\n            {\n                bail!(\n                    \"timer unit '{name}' must set at least one of `on_boot_sec`, \\\n                     `on_unit_active_sec`, `on_unit_inactive_sec`, or `on_calendar`\"\n                );\n            }\n        }\n        if let Some(nice) = config.nice\n            && !(-20..=19).contains(&nice)\n        {","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/systemd.rs#L184-L220","documentation":"Timer units in this config schema must only carry timer-related directives. If a unit is detected as a Timer (it has a schedule field) but also sets service-only directives (`exec_start`, `type`, `remain_after_exit`, `environment`, `standard_output`, `standard_error`, etc.), `from_toml` rejects it and lists the offending fields.","triggerScenarios":"Declaring `[systemd.<name>]` with a schedule key such as `on_calendar` or `on_boot_sec` AND any of the service-only keys (`exec_start`, `type`, `remain_after_exit`, `environment`, `standard_output`, `standard_error`, ...) in the same block.","commonSituations":"Merging a service unit and a timer unit into one config block instead of two; converting an existing service to a timer by just adding `on_boot_sec` without removing service fields.","solutions":["Remove the listed service-only directives from the timer block.","Split into two units: a `[systemd.myapp]` service with `exec_start` and a `[systemd.myapp.timer]` (or similarly named) timer with the schedule.","If you actually want a service, remove the schedule keys (`on_boot_sec`, `on_calendar`, etc.) so the unit is classified as a Service."],"exampleFix":"# before\n[systemd.myapp]\non_boot_sec = 60\nexec_start = \"/usr/bin/myapp\"\n\n# after\n[systemd.myapp]\nexec_start = \"/usr/bin/myapp\"\n[systemd.myapp.timer]\non_boot_sec = 60","handlingStrategy":"validation","validationCode":"const SERVICE_ONLY: &[&str] = &[\"exec_start\", \"type\", \"remain_after_exit\", \"environment\", \"standard_output\", \"standard_error\"];\nconst TIMER_KEYS: &[&str] = &[\"on_boot_sec\", \"on_unit_active_sec\", \"on_unit_inactive_sec\", \"on_calendar\", \"randomized_delay_sec\"];\nfn check_block(cfg: &toml::Value) -> Result<(), String> {\n    let is_timer = TIMER_KEYS.iter().any(|k| cfg.get(k).is_some());\n    if is_timer {\n        let offenders: Vec<_> = SERVICE_ONLY.iter().filter(|k| cfg.get(*k).is_some()).collect();\n        if !offenders.is_empty() { return Err(format!(\"timer block sets service-only keys: {offenders:?}\")); }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep timer and service definitions in separate TOML blocks.","Never add schedule keys to a block that already has `exec_start`.","Document which keys are timer-only vs service-only for your team."],"tags":["systemd","validation","conflicting-config","timers"],"backgroundTag":"conflicting-config-options","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}