jdx/mise · error

user service '{name}': `on_change` only applies to system se

Error message

user service '{name}': `on_change` only applies to system services

What it means

The `on_change` option (restart/reload behavior when the definition changes) is only meaningful for system-level services. Setting a non-default `on_change` on a user service is rejected at parse time because user service management does not implement change-action hooks.

Source

Thrown at src/system/user_services.rs:89

        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!(
                        "user service '{name}' names unknown builtin '{builtin_name}'; available: {}",
                        BUILTIN_NAMES.join(", ")
                    );

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Remove the `on_change` key from the user service entry
  2. Move the service to `[bootstrap.linux.systemd.units]` if you need `on_change` behavior
  3. Leave `on_change` unset to use the default

Example fix

// before
[[bootstrap.linux.user_services]]
name = "my-agent"
command = "my-agent --daemon"
on_change = "restart"

// after
[[bootstrap.linux.user_services]]
name = "my-agent"
command = "my-agent --daemon"
Defensive patterns

Strategy: validation

Validate before calling

fn validate_user_service(s: &UserServiceConfig) -> Result<(), String> {
    if s.on_change != Default::default() {
        return Err(format!("user service '{}': on_change only applies to system services", s.name));
    }
    Ok(())
}

Prevention

When it happens

Trigger: A user service entry with `on_change` set to anything other than the default value, parsed via `from_toml_with_executable` at src/system/user_services.rs:89.

Common situations: Mirroring a system `[bootstrap.linux.systemd.units]` service block into a user service block and keeping its `on_change` key; assuming user and system services share the same option surface.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/b09b70d1c09a19f9. Report an issue: GitHub.