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
- Pick one source of truth: delete the service block from one of the two files named in the error
- Or make both declarations exactly identical (all fields equal) so composition skips the duplicate
- Use `mise bootstrap plan` / config origin output to confirm which files contributed before and after cleanup
- 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
- Keep each service declared in exactly one config layer; use includes instead of re-declaring
- When overriding, delete the other layer's block rather than editing values piecemeal
- Use the conflict message's two `conflict_description` origins to find both files fast
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
- managed path '{}' notifies unconfigured bootstrap service '{
- managed path '{}' notifies unconfigured bootstrap service '{
- `defaults {display}` failed: {}
- `defaults {}` failed: {}
- only available on unix
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/23875b2986243792.
Report an issue: GitHub.