{"record":{"id":"2bc3454e78f2109a","repo":"astrid-runtime/astrid","slug":"durable-capsule-archive-contains-duplicate-path-n","errorCode":null,"errorMessage":"durable capsule archive contains duplicate path {name}","messagePattern":"durable capsule archive contains duplicate path (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":385,"sourceCode":"                    component,\n                    std::path::Component::ParentDir | std::path::Component::RootDir\n                )\n            })\n        {\n            bail!(\"durable capsule archive contains unsafe path\");\n        }\n\n        let entry_type = entry.header().entry_type();\n        if !entry_type.is_dir() && !entry_type.is_file() {\n            bail!(\"durable capsule archive contains a link or special file\");\n        }\n\n        let name = path\n            .to_str()\n            .ok_or_else(|| anyhow::anyhow!(\"durable capsule archive path is not UTF-8\"))?\n            .replace('\\\\', \"/\");\n        if files.contains_key(&name) || directories.contains(&name) {\n            bail!(\"durable capsule archive contains duplicate path {name}\");\n        }\n        if entry_type.is_dir() {\n            if !directories.insert(name) {\n                bail!(\"durable capsule archive contains duplicate directory path\");\n            }\n            continue;\n        }\n\n        let mut bytes = Vec::new();\n        entry\n            .read_to_end(&mut bytes)\n            .with_context(|| format!(\"read durable capsule archive file {name}\"))?;\n        files.insert(name, bytes);\n    }\n    Ok(ArchiveInventory { files, directories })\n}\n\n/// Publish one source directory into the target principal's durable registry.","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L367-L403","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rebuild the archive ensuring each path appears exactly once and separators are normalized to '/'.","Deduplicate entries at archive-creation time (keep the last or fail fast).","Find the offending entry from the error's {name} and remove the extra one from the source tree.","Avoid appending to existing tar files; always create a fresh archive."],"exampleFix":"// before: appending duplicates\n// second run appends same entries to capsule.tgz\n// after: always build a fresh archive with a set of seen paths\nlet mut seen = std::collections::BTreeSet::new();\nif !seen.insert(normalized_name.to_string()) { continue; }","handlingStrategy":"validation","validationCode":"let mut seen = std::collections::BTreeSet::new();\nlet name = path.to_str()?.replace('\\\\', \"/\");\nif !seen.insert(name.clone()) {\n    return Err(format!(\"duplicate archive path {name}\"));\n}","typeGuard":"fn archive_paths_unique(names: &[String]) -> bool {\n    let normalized: std::collections::BTreeSet<_> =\n        names.iter().map(|n| n.replace('\\\\', \"/\")).collect();\n    normalized.len() == names.len()\n}","tryCatchPattern":"match read_verified_durable_package_for_owner(&store, owner, id).await {\n    Ok(pkg) => pkg,\n    Err(e) if e.to_string().contains(\"duplicate path\") => {\n        // rebuild the archive from a fresh, deduplicated source tree\n    },\n    Err(e) => return Err(e),\n}","preventionTips":["Always create a fresh tar; never append to an existing archive.","Normalize path separators to '/' at archive creation.","Validate uniqueness of entries before publishing."],"tags":["archive","tar","duplicate","validation"],"backgroundTag":"file-already-exists","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}