jdx/mise · error

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

Error message

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

What it means

The second mask-combination check in from_toml_with_origin (src/system/services.rs:232): `masked = true` together with `enabled = true` is rejected. A masked unit is symlinked to /dev/null; enabling it would create a symlink in the wants/ tree pointing at nothing, which is at best noise and at worst a boot-time failure, so the pair is invalid by design.

Source

Thrown at src/system/services.rs:232

}

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);
        let desired = self.desired();
        let Some(inspection) = &self.inspection else {
            return self.with_origin(ResourcePlan::new(

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. For masking: set enabled = false (masking makes enabled moot anyway)
  2. For enabling: set masked = false
  3. Check layered configs — one layer may contribute enabled = true while another adds masked = true
  4. Re-run bootstrap after the flags are mutually consistent

Example fix

# before
[bootstrap.services.debug-shell]
masked = true
enabled = true    # -> bail
# after
[bootstrap.services.debug-shell]
masked = true
enabled = false
Defensive patterns

Strategy: validation

Validate before calling

# masked + enabled 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('enabled'):
            print(f"service {name}: masked cannot be enabled")
PY

Prevention

When it happens

Trigger: A service declaration with both `masked = true` and `enabled = true` (enabled defaults may also come into play depending on the config body). Caught during request construction from any config layer.

Common situations: Hardening a machine by masking a service while a copied template still sets enabled = true; enabling a unit and later masking it in another config layer without clearing enabled; defaults merged from a base config producing both flags.

Related errors


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