jdx/mise · error

task cache archive contains duplicate paths

Error message

task cache archive contains duplicate paths

What it means

When ingesting a task-cache archive into the CAS, each entry path is inserted into a BTreeMap of nodes; if the same path appears twice, insert returns Some and mise bails. Duplicate paths would make the restored directory tree ambiguous, so the archive is rejected.

Solutions

  1. Rebuild the archive ensuring each path appears exactly once (create a fresh tar instead of appending).
  2. Inspect duplicates with `tar -tf archive.tar | sort | uniq -d` and remove the offending entries.
  3. Delete the bad cache entry from the remote store and re-run the task to regenerate a clean archive.
  4. Fix the producing script so it replaces entries rather than appending them.

Example fix

// before: appending produces duplicate paths
tar -rf cache.tar dir/file
tar -rf cache.tar dir/file
// after: single pass, no duplicates
tar -cf cache.tar dir
Defensive patterns

Strategy: validation

Validate before calling

const names = entries.map(e => e.path);
const dupes = names.filter((n, i) => names.indexOf(n) !== i);
if (dupes.length) throw new Error(`duplicate archive paths: ${dupes}`);

Prevention

When it happens

Trigger: archive_to_cas encounters two archive members with the identical path — e.g. a tar built by concatenating archives, an archive listing a file both explicitly and via its parent traversal, or a producer that added the same path twice.

Common situations: Archives assembled by appending multiple tar streams (`tar -Af` mistakes); custom cache upload scripts that re-add updated files without replacing old entries; corrupted or maliciously crafted cache payloads from a remote store.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: 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 533346cc37)