{"record":{"id":"a010e02f4831b4e7","repo":"astrid-runtime/astrid","slug":"durable-capsule-archive-contains-duplicate-path","errorCode":null,"errorMessage":"durable capsule archive contains duplicate path","messagePattern":"durable capsule archive contains duplicate path","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":571,"sourceCode":"    }\n    fs::create_dir(destination)\n        .with_context(|| format!(\"create materialization {}\", destination.display()))?;\n    let decoder = flate2::read::GzDecoder::new(Cursor::new(&package.archive));\n    let mut archive = tar::Archive::new(decoder);\n    let mut names = std::collections::BTreeSet::new();\n    for entry in archive.entries().context(\"read durable capsule archive\")? {\n        let mut entry = entry.context(\"read durable capsule archive entry\")?;\n        let path = entry.path().context(\"read durable capsule archive path\")?;\n        if path.is_absolute()\n            || path\n                .components()\n                .any(|component| matches!(component, std::path::Component::ParentDir))\n        {\n            bail!(\"durable capsule archive contains unsafe path\");\n        }\n        let relative = path.to_path_buf();\n        if !names.insert(relative.clone()) {\n            bail!(\"durable capsule archive contains duplicate path\");\n        }\n        let output = destination.join(&relative);\n        if entry.header().entry_type().is_symlink()\n            || entry.header().entry_type().is_hard_link()\n            || entry.header().entry_type().is_block_special()\n            || entry.header().entry_type().is_character_special()\n            || entry.header().entry_type().is_fifo()\n        {\n            bail!(\"durable capsule archive contains a link or special file\");\n        }\n        if entry.header().entry_type().is_dir() {\n            fs::create_dir_all(&output)\n                .with_context(|| format!(\"create materialized directory {}\", output.display()))?;\n            continue;\n        }\n        if !entry.header().entry_type().is_file() {\n            bail!(\"durable capsule archive contains an unsupported entry\");\n        }","sourceCodeStart":553,"sourceCodeEnd":589,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L553-L589","documentation":"The extractor tracks every entry path in a set and rejects the archive if the same relative path appears more than once. Duplicate entries would make the final on-disk content depend on entry order, breaking the exact-bytes verification guarantees of materialization.","triggerScenarios":"Materializing a tar archive that contains two entries with the same relative path — e.g. an archive appended to twice, or built by concatenating two capsule archives.","commonSituations":"A packer bug that adds a file twice; tar --append onto an existing archive; concatenating archives during a botched migration; a tampered archive with an injected duplicate entry.","solutions":["Rebuild the archive with canonical_capsule_archive, which produces one entry per path.","Fix the packer/CI step so it creates a fresh archive rather than appending to an existing one.","Re-download the capsule archive if it came from an external source (may be corrupted or tampered)."],"exampleFix":"// before\n// tar -cvf capsule.tar manifest.toml ...\n// tar -rvf capsule.tar manifest.toml   # duplicate!\n// after\nfs::remove_file(\"capsule.tar\").ok();\n// tar -cvf capsule.tar manifest.toml ...  (single pass)","handlingStrategy":"validation","validationCode":"let mut names = std::collections::HashSet::new();\nfor entry in tar::Archive::new(&bytes[..]).entries()? {\n    let p = entry?.path()?.to_path_buf();\n    if !names.insert(p.clone()) {\n        anyhow::bail!(\"duplicate archive entry: {}\", p.display());\n    }\n}","typeGuard":null,"tryCatchPattern":"match materialize_capsule_package(&pkg, &dest) {\n    Err(e) if e.to_string().contains(\"duplicate path\") => {\n        error!(\"archive malformed (duplicate entries); rebuild it\");\n        rebuild_canonical_archive(&src_dir)?;\n    }\n    other => other,\n}","preventionTips":["Create archives in one pass; never tar --append onto an existing capsule archive.","Use canonical_capsule_archive for packing so duplicates are impossible.","Verify archive bytes before materializing; duplicates indicate corruption or tampering."],"tags":["archive","duplicate-entry","capsule"],"backgroundTag":"invalid-argument-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}