jdx/mise · error

remote cache directory contains duplicate names

Error message

remote cache directory contains duplicate names

What it means

Inside each fetched directory proto, mise collects entry names into one BTreeSet shared across the directories, files, and symlinks lists. A name repeated within the directories list - or colliding with a name already seen - bails with 'remote cache directory contains duplicate names' during restore.

Source

Thrown at src/task/task_cache_store.rs:729

    let mut pending = vec![(PathBuf::new(), root.clone(), BTreeSet::new())];
    let mut nodes = BTreeMap::<PathBuf, RestoredNode>::new();
    while let Some((path, digest, mut ancestors)) = pending.pop() {
        if !ancestors.insert(digest.clone()) {
            bail!("remote cache directory graph contains a cycle");
        }
        let bytes = store.client.get_blob(&digest, DIRECTORY_MEDIA_TYPE).await?;
        let directory: RemoteDirectory = serde_json::from_slice(&bytes)?;
        if canonical_json(&serde_json::to_value(&directory)?)? != bytes {
            bail!("remote cache directory is not canonical JSON");
        }
        if directory.version != 1 {
            bail!("unsupported remote cache directory version");
        }
        let mut names = BTreeSet::new();
        for directory in directory.directories {
            validate_cache_name(&directory.name)?;
            if !names.insert(directory.name.clone()) {
                bail!("remote cache directory contains duplicate names");
            }
            let child = path.join(&directory.name);
            validate_cache_path(&child)?;
            nodes.insert(
                child.clone(),
                RestoredNode::Directory {
                    mode: directory.mode,
                },
            );
            pending.push((child, directory.digest, ancestors.clone()));
        }
        for file in directory.files {
            validate_cache_name(&file.name)?;
            if !names.insert(file.name.clone()) {
                bail!("remote cache directory contains duplicate names");
            }
            let child = path.join(&file.name);
            validate_cache_path(&child)?;

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Purge the entry from the remote cache and re-run the task
  2. Ensure a single-writer mise version across the team
  3. Inspect the directory blob at the failing digest and fix or delete it

Example fix

// directory proto
// before
"directories": [{"name": "out"}, {"name": "out"}]
// after
"directories": [{"name": "out"}]
Defensive patterns

Strategy: fallback

Validate before calling

// when generating protos, enforce unique names before upload:
let mut names = std::collections::BTreeSet::new();
for d in &proto.directories {
    if !names.insert(d.name.clone()) {
        return Err(eyre::bail!("duplicate directory name {}", d.name));
    }
}

Type guard

fn directory_names_unique(directories: &[RemoteDirectoryNode]) -> bool {
    let mut names = std::collections::BTreeSet::new();
    directories.iter().all(|d| names.insert(d.name.clone()))
}

Try / catch

match materialize_remote_tree(&store, &root).await {
    Ok(tree) => tree,
    Err(err) if err.to_string().contains("duplicate names") => {
        warn!("corrupt directory proto at digest; purging entry");
        purge_action_result(&key).await.ok();
        run_task_uncached(&task).await?
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: materialize_remote_tree processes a directory blob whose directories array lists the same name twice (or reuses a name inserted earlier while iterating the entries).

Common situations: Corrupt or hand-merged blobs; non-mise writers producing protos; a server serving a mismatched blob for a digest.

Related errors


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