jdx/mise · error · eyre::Report
[dotfiles]: duplicate OCI file path {path:?}
Error message
[dotfiles]: duplicate OCI file path {path:?} What it means
Thrown while assembling the [dotfiles] OCI layer when two different sources resolve to the same image path with different bytes or modes. add_file is idempotent for identical (contents, mode) pairs, so this fires only on a genuine conflict, not on harmless overlap. It protects the one-path-one-file invariant of the layer before the tar is built.
Source
Thrown at src/oci/builder.rs:990
#[derive(Default)]
struct DotfilesLayerEntries {
files: IndexMap<String, (Vec<u8>, u32)>,
dirs: IndexSet<String>,
}
type DotfilesLayerFile = (String, Vec<u8>, u32);
type DotfilesLayerFiles = Vec<DotfilesLayerFile>;
type DotfilesLayerDirs = Vec<String>;
impl DotfilesLayerEntries {
fn add_file(&mut self, path: String, contents: Vec<u8>, mode: u32) -> Result<()> {
if self.dirs.contains(&path) {
bail!("[dotfiles]: duplicate OCI path {path:?} as both file and directory");
}
if let Some((existing_contents, existing_mode)) = self.files.get(&path) {
if existing_contents != &contents || *existing_mode != mode {
bail!("[dotfiles]: duplicate OCI file path {path:?}");
}
return Ok(());
}
self.files.insert(path, (contents, mode));
Ok(())
}
fn add_dir(&mut self, path: String) -> Result<()> {
if self.files.contains_key(&path) {
bail!("[dotfiles]: duplicate OCI path {path:?} as both file and directory");
}
self.dirs.insert(path);
Ok(())
}
fn into_layer_inputs(self) -> (DotfilesLayerFiles, DotfilesLayerDirs) {
let files = self
.filesView on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Search mise.toml for [dotfiles] entries whose normalized targets (~/x -> root/x, /x -> x) are equal; give each a unique target path.
- If the duplicate is intentional (same file referenced twice), make the source files byte-identical and their modes equal, then add_file dedupes silently.
- Remove the redundant entry entirely and keep one canonical source for that destination path.
Example fix
# before [dotfiles."~/.gitconfig-work"] target = "~/.gitconfig" [dotfiles."~/.gitconfig-home"] target = "/root/.gitconfig" # same image path, different contents # after [dotfiles."~/.gitconfig-work"] target = "~/.gitconfig" [dotfiles."~/.gitconfig-home"] target = "~/.gitconfig-home"
Defensive patterns
Strategy: validation
Validate before calling
# before building, assert no two [dotfiles] targets normalize to the same path
import re, sys
entries = {"~/.gitconfig": "/root/.gitconfig", "~/b": "~/a"} # parsed from mise.toml
def norm(t):
if t == "~": return "root"
if t.startswith("~/"): return "root/" + t[2:]
return t.lstrip("/").replace("\\", "/")
seen = {}
for src, tgt in entries.items():
n = norm(tgt)
if n in seen and seen[n] != src:
sys.exit(f"duplicate target {n!r} from {seen[n]} and {src}")
seen[n] = src Prevention
- Adopt one spelling for home paths in [dotfiles] targets (always ~/...) to avoid accidental collisions.
- When multiple sources must land in one directory, give each a distinct file-name suffix under that directory.
- Run `mise oci build` in CI on every mise.toml change so target conflicts fail the PR, not a later release build.
When it happens
Trigger: Two [dotfiles] entries whose normalized targets collide, e.g. [dotfiles."~/a"] target = "/root/a" and [dotfiles."~/b"] target = "~/a"; or a directory-source walk producing a file at a path another single-file entry already claimed with different contents or a different permission mode.
Common situations: Mapping several dotfiles into the same destination (all dumping into ~/), copying the same file twice via different home spellings (~/.gitconfig vs /root/.gitconfig) after editing one source but not the other, or overlapping directory sources where a file changed between walks.
Related errors
- [dotfiles]."{}": source does not exist: {}
- [dotfiles]."{}": mode symlink-each requires a directory sour
- [dotfiles]: duplicate OCI path {path:?} as both file and dir
- inline content
- oci mount_point must not be empty
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/c2a73e821f56d1ca.
Report an issue: GitHub.