jdx/mise · error

managed directory paths '{previous}' and '{path}' normalize

Error message

managed directory paths '{previous}' and '{path}' normalize to the same target '{}'

What it means

Same-layer duplicate detection as error 604, but for the `[bootstrap.directories]` table: two directory entries in one config file whose declared paths normalize to the same absolute target via absolute_target() (managed_files.rs:364-371). Because directory entries carry owner/group/mode/state, two conflicting declarations cannot be merged field-wise, so mise refuses rather than picking one arbitrarily.

Source

Thrown at src/system/managed_files.rs:369

                        target.display()
                    );
                }
                merged.entry(target).or_insert_with(|| (file, base.clone()));
            }
        }
    }
    Ok(merged)
}

fn directories_from_config(config: &Config) -> Result<Vec<ManagedDirectoryRequest>> {
    let mut merged: IndexMap<PathBuf, ManagedDirectoryTomlConfig> = IndexMap::new();
    for cf in config.config_files.values() {
        if let Some(bootstrap) = cf.bootstrap_config() {
            let mut layer_paths = IndexMap::new();
            for (path, directory) in bootstrap.directories {
                let target = absolute_target(&path)?;
                if let Some(previous) = layer_paths.insert(target.clone(), path.clone()) {
                    bail!(
                        "managed directory paths '{previous}' and '{path}' normalize to the same target '{}'",
                        target.display()
                    );
                }
                merged.entry(target).or_insert(directory);
            }
        }
    }
    merged
        .into_iter()
        .map(|(path, config)| ManagedDirectoryRequest::from_toml(path, config))
        .collect()
}

fn validate_requests(
    files: &[ManagedFileRequest],
    directories: &[ManagedDirectoryRequest],
) -> Result<()> {

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Delete one of the colliding entries and keep the fully-specified one
  2. Normalize path spellings to absolute paths throughout the table to make future collisions obvious at a glance
  3. If duplicate intent was layering (base + override), split the entries across different config files so the merge logic (later layer wins) applies

Example fix

# before
[bootstrap.directories."/srv/app"]
owner = "app"
[bootstrap.directories."/srv/./app"]
owner = "app"

# after
[bootstrap.directories."/srv/app"]
owner = "app"
Defensive patterns

Strategy: validation

Validate before calling

// Same check as 604 but for the directories table
let mut seen = HashSet::new();
for key in bootstrap_directories_keys(config_file) {
    let t = absolute(base_dir, normalize(key));
    assert!(seen.insert(t), "duplicate directory target in this config file");
}

Prevention

When it happens

Trigger: A single mise.toml with `[bootstrap.directories."/srv/app"]` and `[bootstrap.directories."/srv/./app"]` (or `"srv/app"` and `"./srv/app"` relative to the config dir) — string-distinct keys whose normalized absolute targets are identical.

Common situations: Generated config emitted by templates that join paths inconsistently (with/without leading `./` or redundant separators); incrementally appended entries during bootstrap development where the earlier spelling was forgotten; refactors that changed from relative to absolute paths without removing old entries.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/323b7ddc813a5309. Report an issue: GitHub.