jdx/mise · error

bootstrap service '{name}' cannot be both masked and running

Error message

bootstrap service '{name}' cannot be both masked and running

What it means

When building a ServiceRequest from TOML (from_toml_with_origin, src/system/services.rs:229), mise rejects the combination masked = true and state = "running": a masked unit's binary is symlinked to /dev/null, so systemd cannot start it — the desired state is unsatisfiable by construction.

Source

Thrown at src/system/services.rs:229

    for request in requests {
        request.inspection = Some(inspect_service(&systemctl, &request.unit));
    }
}

impl ServiceRequest {
    #[cfg(test)]
    fn from_toml(name: String, config: ServiceTomlConfig) -> Result<Self> {
        Self::from_toml_with_origin(name, config, None)
    }

    fn from_toml_with_origin(
        name: String,
        config: ServiceTomlConfig,
        origin: Option<ResourceOrigin>,
    ) -> Result<Self> {
        let unit = normalize_unit_name(&name)?;
        if config.masked && config.state == ServiceState::Running {
            bail!("bootstrap service '{name}' cannot be both masked and running");
        }
        if config.masked && config.enabled {
            bail!("bootstrap service '{name}' cannot be both masked and enabled");
        }
        Ok(Self {
            name,
            unit,
            state: config.state,
            enabled: config.enabled,
            masked: config.masked,
            on_change: config.on_change,
            origin,
            inspection: None,
        })
    }

    pub(crate) fn plan(&self) -> ResourcePlan {
        let id = ResourceId::new("service", &self.name);

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. If the service must be masked: set its state to stopped (or omit state) — masking already guarantees it cannot run
  2. If the service must run: set masked = false (and optionally enabled = true)
  3. If you only wanted it disabled at boot: use enabled = false instead of masked
  4. Re-run bootstrap; the request builds and planning proceeds

Example fix

# before
[bootstrap.services.telnet]
masked = true
state = "running"   # -> bail
# after
[bootstrap.services.telnet]
masked = true
state = "stopped"
Defensive patterns

Strategy: validation

Validate before calling

# masked + running is always invalid — catch it in config lint
python3 - <<'PY'
import tomllib
svc = tomllib.load(open('mise.toml','rb')).get('bootstrap',{}).get('services',{})
if isinstance(svc, dict):
    for name, body in svc.items():
        if isinstance(body,dict) and body.get('masked') and body.get('state')=='running':
            print(f"service {name}: masked cannot be running")
PY

Prevention

When it happens

Trigger: Declaring a service with `masked = true` together with `state = "running"` in any bootstrap config layer. Validated at request-construction time, before the plan or systemctl runs.

Common situations: Copy-pasting a service block and toggling masked for a 'disable it' use case without changing state; merging two config fragments that together set both fields; misunderstanding masked as a softer version of disabled.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/a02e62b8514d428b. Report an issue: GitHub.