jdx/mise · error
user service '{name}' cannot be masked; use `state = "absent
Error message
user service '{name}' cannot be masked; use `state = "absent"` to remove it What it means
User services managed by mise do not support the systemd 'masked' state. If a user service entry sets `masked = true`, parsing fails immediately because masking a user unit is not implemented; the library directs you to remove the service with `state = "absent"` instead. This is a fail-fast validation in `from_toml_with_executable` so bad config is rejected before any system mutation.
Source
Thrown at src/system/user_services.rs:86
config: ServiceTomlConfig,
origin: Option<ResourceOrigin>,
) -> Result<Self> {
Self::from_toml_with_executable(name, config, origin, durable_mise_executable())
}
fn from_toml_with_executable(
name: String,
config: ServiceTomlConfig,
origin: Option<ResourceOrigin>,
executable: Option<PathBuf>,
) -> Result<Self> {
if !valid_name(&name) {
bail!(
"user service name '{name}' must contain only letters, numbers, '.', '_', or '-'"
);
}
if config.masked {
bail!("user service '{name}' cannot be masked; use `state = \"absent\"` to remove it");
}
if config.on_change != super::services_common::ServiceChangeAction::default() {
bail!("user service '{name}': `on_change` only applies to system services");
}
let mut description = config.description;
let mut restart = config.restart;
let mut nice = None;
let mut unresolved = None;
let command = match (config.builtin.as_deref(), config.command.as_deref()) {
(Some(_), Some(_)) => {
bail!("user service '{name}' sets both `builtin` and `command`; choose one")
}
(None, None) => {
bail!("user service '{name}' must set `command` or `builtin`")
}
(Some(builtin_name), None) => {
let Some(definition) = builtin(builtin_name) else {
bail!(View on GitHub (pinned to afd2eddd3a)
Solutions
- Set `masked = false` (or delete the `masked` key) on the user service entry
- If the goal is to remove the service, set `state = "absent"` instead of masking
- If the goal is to prevent startup, remove the entry from config entirely
Example fix
// before [[bootstrap.linux.user_services]] name = "pulseaudio" command = "pulseaudio" masked = true // after [[bootstrap.linux.user_services]] name = "pulseaudio" command = "pulseaudio" state = "absent"
Defensive patterns
Strategy: validation
Validate before calling
fn validate_user_service(s: &UserServiceConfig) -> Result<(), String> {
if s.masked {
return Err(format!("user service '{}' cannot be masked; use state = \"absent\"", s.name));
}
Ok(())
} Prevention
- Never set `masked` on user services; masking is a system-service concept
- Use `state = "absent"` to remove services
- Review user service blocks when copying from system service config
When it happens
Trigger: Declaring a `[bootstrap.*.user_services]` (or equivalent) entry whose parsed config has `masked = true`; raised by `from_toml_with_executable` in src/system/user_services.rs:86 during config parsing.
Common situations: Copying a systemd unit config that used `Masked=true` into a mise user service block; trying to disable a user service by masking it instead of setting its state to absent.
Related errors
- 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, '.',
- service unit '{name}' must set a non-empty `exec_start`
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/71a6ddfd7cde2860.
Report an issue: GitHub.