jdx/mise · error
timer unit '{name}' cannot set service-only directive(s): {}
Error message
timer unit '{name}' cannot set service-only directive(s): {} What it means
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.
Source
Thrown at src/system/systemd.rs:202
(config.timeout_start_sec.is_some(), "timeout_start_sec"),
(config.timeout_stop_sec.is_some(), "timeout_stop_sec"),
(config.no_new_privileges.is_some(), "no_new_privileges"),
(config.private_tmp.is_some(), "private_tmp"),
(!config.environment.is_empty(), "environment"),
(!config.environment_file.is_empty(), "environment_file"),
(config.nice.is_some(), "nice"),
(config.umask.is_some(), "umask"),
(config.working_directory.is_some(), "working_directory"),
(config.restart.is_some(), "restart"),
(config.restart_sec.is_some(), "restart_sec"),
(config.standard_output.is_some(), "standard_output"),
(config.standard_error.is_some(), "standard_error"),
]
.into_iter()
.filter_map(|(is_set, field)| is_set.then_some(field))
.collect::<Vec<_>>();
if !service_only_fields.is_empty() {
bail!(
"timer unit '{name}' cannot set service-only directive(s): {}",
service_only_fields.join(", ")
);
}
if config.on_boot_sec.is_none()
&& config.on_unit_active_sec.is_none()
&& config.on_unit_inactive_sec.is_none()
&& config.on_calendar.is_none()
{
bail!(
"timer unit '{name}' must set at least one of `on_boot_sec`, \
`on_unit_active_sec`, `on_unit_inactive_sec`, or `on_calendar`"
);
}
}
if let Some(nice) = config.nice
&& !(-20..=19).contains(&nice)
{View on GitHub (pinned to afd2eddd3a)
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.
Example fix
# before [systemd.myapp] on_boot_sec = 60 exec_start = "/usr/bin/myapp" # after [systemd.myapp] exec_start = "/usr/bin/myapp" [systemd.myapp.timer] on_boot_sec = 60
Defensive patterns
Strategy: validation
Validate before calling
const SERVICE_ONLY: &[&str] = &["exec_start", "type", "remain_after_exit", "environment", "standard_output", "standard_error"];
const TIMER_KEYS: &[&str] = &["on_boot_sec", "on_unit_active_sec", "on_unit_inactive_sec", "on_calendar", "randomized_delay_sec"];
fn check_block(cfg: &toml::Value) -> Result<(), String> {
let is_timer = TIMER_KEYS.iter().any(|k| cfg.get(k).is_some());
if is_timer {
let offenders: Vec<_> = SERVICE_ONLY.iter().filter(|k| cfg.get(*k).is_some()).collect();
if !offenders.is_empty() { return Err(format!("timer block sets service-only keys: {offenders:?}")); }
}
Ok(())
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- timer unit '{name}' must set at least one of `on_boot_sec`,
- bootstrap service '{name}' cannot be both masked and running
- bootstrap service '{name}' cannot be both masked and enabled
- invalid bootstrap service name '{name}': use at most 255 ASC
- unit name '{name}' must contain only letters, numbers, '.',
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/eff1e19779ed0424.
Report an issue: GitHub.