jdx/mise · error
timer unit ' ' must set at least one of `on_boot_sec`…
Error message
timer unit '{name}' must set at least one of `on_boot_sec`, `on_unit_active_sec`, `on_unit_inactive_sec`, or `on_calendar` What it means
A unit classified as a Timer must carry at least one scheduling directive: on_boot_sec, on_unit_active_sec, on_unit_inactive_sec, or on_calendar. from_toml rejects timer entries with none of these because systemd would create a timer that never elapses.
Solutions
- Add a schedule key, e.g. on_calendar = "daily" or on_boot_sec = 30
- If no schedule is wanted, convert the entry to a service by removing timer-ish keys and providing exec_start
- Remove the placeholder entry until the schedule is decided
Example fix
# before (mise.toml) [systemd."cleanup.timer"] randomized_delay_sec = 60 # after [systemd."cleanup.timer"] on_calendar = "daily" randomized_delay_sec = 60
Defensive patterns
Strategy: validation
Validate before calling
let has_schedule = on_boot_sec.is_some() || on_unit_active_sec.is_some()
|| on_unit_inactive_sec.is_some() || on_calendar.is_some();
if !has_schedule { bail!("timer entry needs on_boot_sec / on_unit_active_sec / on_unit_inactive_sec / on_calendar"); } Prevention
- Add a schedule key whenever you create a timer entry — fill the placeholder immediately
- randomized_delay_sec alone does not schedule anything
- Review mise.toml diffs to ensure schedule lines aren't accidentally deleted
When it happens
Trigger: Defining a unit in mise.toml whose name/config ends up as a Timer (e.g. randomized_delay_sec present, or intended as a timer) without setting any of the four scheduling keys, then loading it via from_toml.
Common situations: Scaffolding a timer entry and planning to fill in the schedule later; accidentally deleting the on_calendar line; setting only randomized_delay_sec believing it schedules the unit (it only jitters an existing schedule).
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- service unit ' ' must set a non-empty `exec_start
- timer unit ' ' cannot set service-only directive(s)
- bootstrap service ' ' sets , which only applies to `scope =…
- managed path ' ' notifies user-scope bootstrap service ' '…
- service unit ' ' has invalid `nice` value ; expected -20…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/17fe54615ee8cf4e.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/systemd.rs:212
(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)
{
bail!("service unit '{name}' has invalid `nice` value {nice}; expected -20 through 19");
}
if let Some(umask) = &config.umask
&& !valid_umask(umask)
{
bail!(
"service unit '{name}' has invalid `umask` value '{umask}'; expected an octal access mask from 0000 through 0777"
);
}
let wanted_by = config.wanted_by.unwrap_or_else(|| match kind {View on GitHub (pinned to 533346cc37)