jdx/mise · error
unit name ' ' must contain only letters, numbers, '.', '_'…
Error message
unit name '{name}' must contain only letters, numbers, '.', '_', '-', or '@' What it means
SystemdRequest::from_toml validates unit names from mise.toml systemd config against valid_name(), which permits only letters, numbers, '.', '_', '-', and '@'. A name containing any other character (spaces, slashes, colons, etc.) is rejected before a unit file is generated, preventing malformed or unsafe systemd unit names.
Solutions
- Rename the unit to only use letters, numbers, '.', '_', '-', '@' (e.g. 'my-worker.service')
- Move descriptive text into config fields like description/comment, not the unit name
- Check for accidental whitespace or trailing characters in the TOML key
Example fix
# before (mise.toml) [systemd."my app.service"] exec_start = "/usr/bin/myapp" # after [systemd."my-app.service"] exec_start = "/usr/bin/myapp"
Defensive patterns
Strategy: validation
Validate before calling
fn valid_unit_name(name: &str) -> bool {
!name.is_empty()
&& name.chars().all(|c| c.is_ascii_alphanumeric() || "._-@".contains(c))
}
// check before writing the TOML entry Prevention
- Use kebab-case or dot-separated names for systemd units (e.g. my-app.service)
- Never put spaces, slashes, or colons in unit names
- Put human-readable descriptions in dedicated fields, not the unit key
When it happens
Trigger: Defining a systemd unit in mise.toml ([systemd] or equivalent table) whose key/name contains characters outside [A-Za-z0-9._@-], then running the command that loads systemd requests via from_toml.
Common situations: Copy-pasting a unit description with spaces into the name field; using a path-like name such as 'my/app.service'; typos like 'worker:one.service'; shell-interpolated names.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- bootstrap service ' ' sets , which only applies to `scope =…
- invalid bootstrap secret name
- invalid bootstrap service name
- 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/8d121fa53f67e499.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/systemd.rs:159
pub active: bool,
pub enabled: bool,
pub state: SystemdState,
}
impl SystemdStatus {
pub(crate) fn is_desired(&self) -> bool {
match self.state {
SystemdState::Active => self.request.start,
SystemdState::Inactive => !self.request.start,
SystemdState::Differs | SystemdState::Missing => false,
}
}
}
impl SystemdRequest {
pub(crate) fn from_toml(name: String, config: SystemdTomlConfig) -> Result<Self> {
if !valid_name(&name) {
bail!("unit name '{name}' must contain only letters, numbers, '.', '_', '-', or '@'");
}
let is_timer = config.on_boot_sec.is_some()
|| config.on_unit_active_sec.is_some()
|| config.on_unit_inactive_sec.is_some()
|| config.on_calendar.is_some()
|| config.randomized_delay_sec.is_some()
|| config.accuracy_sec.is_some()
|| config.persistent.is_some()
|| config.unit.is_some();
let kind = if is_timer {
SystemdUnitKind::Timer
} else {
SystemdUnitKind::Service
};
let exec_start = config.exec_start.map(|s| s.trim().to_string());
if kind == SystemdUnitKind::Service && exec_start.as_deref().is_none_or(str::is_empty) {
bail!("service unit '{name}' must set a non-empty `exec_start`");
}View on GitHub (pinned to 533346cc37)