astrid-runtime/astrid · error

durable capsule archive contains duplicate path {name}

Error message

durable capsule archive contains duplicate path {name}

What it means

read_archive_files encountered a path that already exists in the file map or directory set, i.e. the archive contains two entries that normalize to the same name (backslashes are normalized to '/'). Duplicate paths make archive content ambiguous, so the library rejects the package rather than guessing which entry wins.

Source

Thrown at crates/astrid-capsule-install/src/storage.rs:385

                    component,
                    std::path::Component::ParentDir | std::path::Component::RootDir
                )
            })
        {
            bail!("durable capsule archive contains unsafe path");
        }

        let entry_type = entry.header().entry_type();
        if !entry_type.is_dir() && !entry_type.is_file() {
            bail!("durable capsule archive contains a link or special file");
        }

        let name = path
            .to_str()
            .ok_or_else(|| anyhow::anyhow!("durable capsule archive path is not UTF-8"))?
            .replace('\\', "/");
        if files.contains_key(&name) || directories.contains(&name) {
            bail!("durable capsule archive contains duplicate path {name}");
        }
        if entry_type.is_dir() {
            if !directories.insert(name) {
                bail!("durable capsule archive contains duplicate directory path");
            }
            continue;
        }

        let mut bytes = Vec::new();
        entry
            .read_to_end(&mut bytes)
            .with_context(|| format!("read durable capsule archive file {name}"))?;
        files.insert(name, bytes);
    }
    Ok(ArchiveInventory { files, directories })
}

/// Publish one source directory into the target principal's durable registry.

View on GitHub (pinned to affd8760f4)

Solutions

  1. Rebuild the archive ensuring each path appears exactly once and separators are normalized to '/'.
  2. Deduplicate entries at archive-creation time (keep the last or fail fast).
  3. Find the offending entry from the error's {name} and remove the extra one from the source tree.
  4. Avoid appending to existing tar files; always create a fresh archive.

Example fix

// before: appending duplicates
// second run appends same entries to capsule.tgz
// after: always build a fresh archive with a set of seen paths
let mut seen = std::collections::BTreeSet::new();
if !seen.insert(normalized_name.to_string()) { continue; }
Defensive patterns

Strategy: validation

Validate before calling

let mut seen = std::collections::BTreeSet::new();
let name = path.to_str()?.replace('\\', "/");
if !seen.insert(name.clone()) {
    return Err(format!("duplicate archive path {name}"));
}

Type guard

fn archive_paths_unique(names: &[String]) -> bool {
    let normalized: std::collections::BTreeSet<_> =
        names.iter().map(|n| n.replace('\\', "/")).collect();
    normalized.len() == names.len()
}

Try / catch

match read_verified_durable_package_for_owner(&store, owner, id).await {
    Ok(pkg) => pkg,
    Err(e) if e.to_string().contains("duplicate path") => {
        // rebuild the archive from a fresh, deduplicated source tree
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: read_archive_files on an archive where two entries share a normalized path (e.g. "a/b" and "a\\b", or the same file listed twice), and files/directories already contain that name.

Common situations: Concatenating or patching tar archives; Windows-generated archives mixing path separators; archive builders run twice appending to the same tar; case- or separator-insensitive filesystems producing colliding entries.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/2bc3454e78f2109a. Report an issue: GitHub.