{"record":{"id":"8d121fa53f67e499","repo":"jdx/mise","slug":"unit-name-name-must-contain-only-letters-numb","errorCode":null,"errorMessage":"unit name '{name}' must contain only letters, numbers, '.', '_', '-', or '@'","messagePattern":"unit name '(.+?)' must contain only letters, numbers, '\\.', '_', '-', or '@'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/systemd.rs","lineNumber":159,"sourceCode":"    pub active: bool,\n    pub enabled: bool,\n    pub state: SystemdState,\n}\n\nimpl SystemdStatus {\n    pub(crate) fn is_desired(&self) -> bool {\n        match self.state {\n            SystemdState::Active => self.request.start,\n            SystemdState::Inactive => !self.request.start,\n            SystemdState::Differs | SystemdState::Missing => false,\n        }\n    }\n}\n\nimpl SystemdRequest {\n    pub(crate) fn from_toml(name: String, config: SystemdTomlConfig) -> Result<Self> {\n        if !valid_name(&name) {\n            bail!(\"unit name '{name}' must contain only letters, numbers, '.', '_', '-', or '@'\");\n        }\n        let is_timer = config.on_boot_sec.is_some()\n            || config.on_unit_active_sec.is_some()\n            || config.on_unit_inactive_sec.is_some()\n            || config.on_calendar.is_some()\n            || config.randomized_delay_sec.is_some()\n            || config.accuracy_sec.is_some()\n            || config.persistent.is_some()\n            || config.unit.is_some();\n        let kind = if is_timer {\n            SystemdUnitKind::Timer\n        } else {\n            SystemdUnitKind::Service\n        };\n        let exec_start = config.exec_start.map(|s| s.trim().to_string());\n        if kind == SystemdUnitKind::Service && exec_start.as_deref().is_none_or(str::is_empty) {\n            bail!(\"service unit '{name}' must set a non-empty `exec_start`\");\n        }","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/systemd.rs#L141-L177","documentation":"Systemd unit names are validated at parse time in `SystemdRequest::from_toml`. A name containing characters outside the allowed set (letters, numbers, `.`, `_`, `-`, `@`) is rejected because systemd itself would refuse or misinterpret such a unit name. This is a fail-fast schema validation before any systemctl interaction.","triggerScenarios":"Defining a `[systemd.<name>]` block in mise.toml whose key contains whitespace, `/`, `:`, or other special characters, which then flows into `SystemdRequest::from_toml` and fails `valid_name`.","commonSituations":"Typos or pasted names like `my service.service`, `app:prod`, or names with spaces; template placeholders left unexpanded; copied unit names with parameters written incorrectly.","solutions":["Rename the TOML key to contain only letters, numbers, `.`, `_`, `-`, or `@`.","Remove stray whitespace or path separators from the unit name.","For templated units, use the `@` form (e.g. `app@.service`) rather than other special characters."],"exampleFix":"# before\n[systemd.\"my app:prod\"]\nexec_start = \"/usr/bin/app\"\n\n# after\n[systemd.\"my-app-prod.service\"]\nexec_start = \"/usr/bin/app\"","handlingStrategy":"validation","validationCode":"fn valid_unit_name(name: &str) -> bool {\n    !name.is_empty()\n        && name.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-' | '@'))\n}\nassert!(valid_unit_name(\"my-app-prod.service\"));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep unit names to `[A-Za-z0-9._@-]` when authoring mise.toml blocks.","Avoid TOML keys generated from user input without sanitization.","Use hyphens instead of spaces or colons in environment-suffixed names."],"tags":["systemd","validation","naming","config"],"backgroundTag":"invalid-identifier-format","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}