jdx/mise · error

task cache archive contains duplicate paths

Error message

task cache archive contains duplicate paths

What it means

The archive walker builds a map of path → node and refuses duplicates: two entries claiming the same path (e.g. a file and a directory at the same name, or the same file listed twice) would make the cached directory tree ambiguous. The insert returning Some triggers this error.

Source

Thrown at src/task/task_cache_store.rs:613

                    size,
                },
                executable: mode & 0o111 != 0,
                mode,
                file: temporary,
            }
        } else if entry_type == EntryType::Symlink {
            let target = entry
                .header()
                .link_name()
                .ok_or_else(|| eyre!("remote cache symlink is missing its target"))?
                .into_owned();
            validate_cache_symlink_target(&entry_path, &target)?;
            ArchiveNode::Symlink { mode, target }
        } else {
            bail!("unsupported task cache archive entry type");
        };
        if nodes.insert(entry_path.clone(), node).is_some() {
            bail!("task cache archive contains duplicate paths");
        }
        let mut parent = entry_path.parent();
        while let Some(path) = parent {
            nodes
                .entry(path.to_path_buf())
                .or_insert(ArchiveNode::Directory { mode: 0o755 });
            parent = path.parent();
        }
    }

    fn build_directory(
        path: &Path,
        nodes: &BTreeMap<PathBuf, ArchiveNode>,
        directory_uploads: &mut Vec<BlobUpload>,
    ) -> Result<CacheDigest> {
        let mut directories = Vec::new();
        let mut files = Vec::new();
        let mut symlinks = Vec::new();

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Rebuild the output/archive so each path appears exactly once.
  2. Rename one of the conflicting entries (a file cannot share a path with a directory).
  3. Fix the packaging tool to deduplicate or to use distinct directory prefixes (e.g. "a/" vs "a.txt").

Example fix

// before
// entries: ["out" (dir), "out" (file)]
// after
// entries: ["out" (dir), "out/result.txt" (file)]
Defensive patterns

Strategy: validation

Validate before calling

fn paths_unique(entries: &[PathBuf]) -> bool {
    let mut seen = std::collections::HashSet::new();
    entries.iter().all(|p| seen.insert(p.clone()))
}

Try / catch

match commit(&out).await {
    Err(e) if e.to_string().contains("duplicate paths") => {
        // deduplicate/rebuild the archive and retry once
    }
    r => r?,
}

Prevention

When it happens

Trigger: archive_to_cas encountering two entries with the identical entry_path — e.g. an archive containing both "a" as a file and "a/b" entries, or a literally duplicated path entry.

Common situations: Archives produced by buggy packaging scripts that append twice; tar files where a path first appears as a directory prefix (auto-inserted) and later as a file; non-deterministic build outputs rebuilt mid-archive.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/15abf26c50be47d1. Report an issue: GitHub.