jdx/mise · error

conflicting bootstrap service declarations for {name} fir

Error message

conflicting bootstrap service declarations for {name}

  first:
    {}

  second:
    {}

What it means

When composing bootstrap service declarations across config layers (project, local, global and other `bootstrap_config_maps` sources), mise allows the same service name only if every declaration is byte-identical. Two declarations of the same name that differ in any field abort config loading, with the origin of each shown in the message.

Source

Thrown at src/system/services_non_linux.rs:85

    fn notify(&mut self, source: ResourceId, services: &[String]) {
        for service in services {
            self.sources
                .entry(service.clone())
                .or_default()
                .insert(source.clone());
        }
    }
}

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);
        }
    }
    Ok(composed
        .into_iter()
        .map(|(name, _)| ServiceRequest { name })
        .collect())
}

fn services_from_config_files(
    config_files: &ConfigMap,
) -> IndexMap<String, (ServiceTomlConfig, ResourceOrigin)> {
    let mut merged = IndexMap::new();

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Pick one source of truth: delete the service block from one of the two files named in the error
  2. Or make both declarations exactly identical (all fields equal) so composition skips the duplicate
  3. Use `mise bootstrap plan` / config origin output to confirm which files contributed before and after cleanup
  4. Split differing intents into two differently-named services if both are genuinely wanted

Example fix

# before
# ~/.config/mise/config.toml
[bootstrap.services.caddy]
state = "running"
on_change = "restart"

# ./mise.toml (project)
[bootstrap.services.caddy]
state = "stopped"

# after: keep it only in the project file, delete the global block
Defensive patterns

Strategy: validation

Validate before calling

mise bootstrap plan 2>&1 >/dev/null | grep -A4 'conflicting bootstrap service' || true
# also: search every loaded config for duplicate service tables
for f in mise.toml mise.local.toml ~/.config/mise/config.toml; do [ -f "$f" ] && grep -n '^\[bootstrap.services\.' "$f"; done | sort | uniq -d

Prevention

When it happens

Trigger: Two mise config files that both load (e.g. `~/.config/mise/config.toml` and the project `mise.toml`, or a local override) each define `[bootstrap.services.<name>]` with different values for state/enabled/masked/on_change.

Common situations: Team-wide global config sets a service and a developer overrides it locally with different settings instead of removing one; copied config files drift apart; a renamed field on one side makes previously-identical blocks differ.

Related errors


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