jdx/mise · error

conflicting bootstrap service declarations for {name}\n\n f

Error message

conflicting bootstrap service declarations for {name}\n\n  first:\n    {}\n\n  second:\n    {}

What it means

Service declarations are collected from every bootstrap config layer (prepare_requests_from_config, src/system/services.rs:150). When two layers declare the same service name, identical declarations are merged silently — but if the TOML bodies differ, bootstrap bails, printing the origin (file/section) of both the first and second declaration so you can see exactly which files fight.

Source

Thrown at src/system/services.rs:150

    dependency_changed: bool,
    notified: bool,
    active: bool,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
struct ServicePlan {
    actions: Vec<ServiceAction>,
}

pub(crate) fn prepare_requests_from_config(config: &Config) -> Result<Vec<ServiceRequest>> {
    let mut composed: IndexMap<String, (ServiceTomlConfig, ResourceOrigin)> = IndexMap::new();
    for config_files in config.bootstrap_config_maps() {
        for (name, declaration) in services_from_config_files(config_files) {
            if let Some(existing) = composed.get(&name) {
                if existing.0 == declaration.0 {
                    continue;
                }
                bail!(
                    "conflicting bootstrap service declarations for {name}\n\n  first:\n    {}\n\n  second:\n    {}",
                    existing.1.conflict_description(),
                    declaration.1.conflict_description(),
                );
            }
            composed.insert(name, declaration);
        }
    }
    composed
        .into_iter()
        .map(|(name, (config, origin))| {
            ServiceRequest::from_toml_with_origin(name, config, Some(origin))
        })
        .collect()
}

fn services_from_config_files(
    config_files: &ConfigMap,

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Open both files named in the 'first:'/'second:' blocks of the message and diff the two service declarations
  2. Make them byte-identical (then the duplicate is harmless and merged), or
  3. Delete the declaration from the layer that should not own it — one owner per service
  4. Re-run bootstrap; collection succeeds once names no longer collide with differing bodies

Example fix

# before: ./mise.toml has
[bootstrap.services.nginx]
state = "running"
# ~/.config/mise/config.toml has
[bootstrap.services.nginx]
state = "stopped"   # -> bail with both origins
# after: keep it only in ./mise.toml (delete the user-level block)
Defensive patterns

Strategy: validation

Validate before calling

# diff service declarations across config layers before bootstrap runs
python3 - <<'PY'
import tomllib, glob, os, collections
seen = {}
files = ['mise.toml'] + glob.glob(os.path.expanduser('~/.config/mise/*.toml'))
for f in files:
    svc = tomllib.load(open(f,'rb')).get('bootstrap',{}).get('services',{})
    if not isinstance(svc, dict): continue
    for name, body in svc.items():
        if name in seen and seen[name] != body:
            print(f"conflicting declarations for service {name}: {seen[name]['_file']} vs {f}")
        body = dict(body); body['_file'] = f
        seen.setdefault(name, body)
PY

Prevention

When it happens

Trigger: The same service name declared in two config files (project mise.toml plus user/global config, or multiple included files) with any difference in state, enabled, masked, or on_change fields. The conflict_description() values in the message identify both origins.

Common situations: Overriding a machine-wide service setting per-project instead of fully re-declaring it identically; an old config copy left in a parent directory; teams share a base config and a developer tweaked one copy.

Related errors


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