jdx/mise · error
managed file paths '{previous}' and '{path}' normalize to th
Error message
managed file paths '{previous}' and '{path}' normalize to the same target '{}' What it means
While merging `[bootstrap.files]` across config layers, two entries within the SAME config layer produced the same absolute normalized target path. `absolute_target()` canonicalizes the declared path (resolving relative paths and normalization), so distinct-looking keys like "etc/app.conf" and "./etc/app.conf" — or "etc/app.conf" plus a trailing-slash/dot-segment variant — collapse to one target; the per-layer `layer_paths` IndexMap detects the collision (managed_files.rs:344-351). Across different layers, later declarations override earlier ones by design; only same-layer duplicates error.
Source
Thrown at src/system/managed_files.rs:349
fn merged_files_from_config(
config: &Config,
) -> Result<IndexMap<PathBuf, (ManagedFileTomlConfig, PathBuf)>> {
let mut merged: IndexMap<PathBuf, (ManagedFileTomlConfig, PathBuf)> = IndexMap::new();
// Config files are ordered from highest to lowest precedence. Preserve the
// first declaration of a target so a parent or global layer cannot replace
// the nearer project declaration.
for cf in config.config_files.values() {
if let Some(bootstrap) = cf.bootstrap_config() {
let mut layer_paths = IndexMap::new();
let base = cf
.get_path()
.parent()
.unwrap_or_else(|| Path::new("."))
.to_path_buf();
for (path, file) in bootstrap.files {
let target = absolute_target(&path)?;
if let Some(previous) = layer_paths.insert(target.clone(), path.clone()) {
bail!(
"managed file paths '{previous}' and '{path}' normalize to the same target '{}'",
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)?;View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Deduplicate the two entries — delete one; they manage the same file, so one fully-specified entry is enough
- Pick a single spelling convention (absolute paths, or relative to the config file) for the whole table
- If both entries were intentional because you wanted different states per layer, move them into different config layers (e.g. project mise.toml vs ~/.config/mise/mise.toml) where merge-by-override applies instead of erroring
Example fix
# before (same file, two spellings, one layer) [bootstrap.files."/etc/app.conf"] content = "a" [bootstrap.files."/etc/./app.conf"] content = "b" # after [bootstrap.files."/etc/app.conf"] content = "a"
Defensive patterns
Strategy: validation
Validate before calling
// Same-layer duplicate check before mise sees it (per config file)
use std::collections::HashSet;
use std::path::{Path, Component};
fn norm(p: &Path) -> Path { p.components().collect::<Vec<Component>>().into_iter().collect() }
let mut seen = HashSet::new();
for key in bootstrap_files_keys(config_file) {
let t = absolute(base_dir, norm(&key));
assert!(seen.insert(t), "duplicate file target in this config file");
} Prevention
- Use absolute paths consistently in [bootstrap.files] so duplicates are visually obvious
- Never mix './x' and 'x' spellings in the same table
- Lint generated config with a dedupe-on-normalized-path script before committing
When it happens
Trigger: One mise.toml containing e.g. `[bootstrap.files."/etc/app.conf"]` and `[bootstrap.files."/etc/./app.conf"]`, or relative variants like `files.cfg` and `./files.cfg` that both resolve against the config file's parent dir to the same absolute path. TOML duplicate keys that are literally identical are rejected by the TOML parser itself, so this error is specifically about paths that differ as strings but normalize identically.
Common situations: Appending a file entry generated by a script that sometimes prefixes `./`; mixing absolute and relative spellings of the same path; normalizing differences introduced by copying config between projects; symlinky path spellings like `/var/../etc/x`.
Related errors
- managed directory paths '{previous}' and '{path}' normalize
- managed system path '{}' is declared as both a file and a di
- managed path '{}' cannot be present while managed ancestor '
- [bootstrap.files]."{}": source and content are mutually excl
- [bootstrap.files]."{}": present files require source or cont
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/c59bdb7c9b28f7dc.
Report an issue: GitHub.