astrid-runtime/astrid · error
capsule archive contains duplicate entry '{path}'
Error message
capsule archive contains duplicate entry '{path}' What it means
After identity checks, verify_release_manifest requires the manifest's version, tag, source_commit and release_workflow_identity to equal the corresponding fields of the signed channel pointer. This ensures the manifest actually describes the exact release the signed pointer attests to. A mismatch means the manifest and pointer are from different releases or one of them was tampered with or stale.
Source
Thrown at crates/astrid-build/src/artifact.rs:260
read_archive_reader(GzDecoder::new(file))
}
fn read_archive_reader<R: Read>(
reader: R,
) -> anyhow::Result<(Vec<ContentRecord>, Option<Vec<u8>>)> {
let mut archive = tar::Archive::new(reader);
let mut records = Vec::new();
let mut envelope = None;
let mut seen = HashSet::new();
for entry in archive
.entries()
.context("failed to read capsule archive")?
{
let mut entry = entry.context("failed to read capsule archive entry")?;
let path = normalized_entry_path(&entry)?;
if !seen.insert(path.clone()) {
bail!("capsule archive contains duplicate entry '{path}'");
}
let kind = entry.header().entry_type();
if kind.is_dir() {
continue;
}
if !kind.is_file() {
bail!("capsule archive contains unsupported entry '{path}'");
}
if path == PROVENANCE_FILE {
if entry.size() > 64 * 1024 {
bail!("capsule provenance envelope exceeds 64 KiB");
}
let mut bytes = Vec::new();
entry
.read_to_end(&mut bytes)
.context("failed to read capsule provenance")?;
envelope = Some(bytes);
continue;View on GitHub (pinned to affd8760f4)
Solutions
- Re-fetch both the channel pointer and the manifest from the authoritative source and retry (rules out stale caches).
- If the release was rebuilt, regenerate both the manifest and the signed pointer from the same build so version/tag/source_commit/workflow_identity agree.
- Fix the publish pipeline to update the pointer atomically with the manifest.
Example fix
# before: pointer for 1.2.3, manifest says version = "1.2.2" # after version = "1.2.3" tag = "v1.2.3" source_commit = "<same as pointer.release.source_commit>"
Defensive patterns
Strategy: retry
Validate before calling
fn manifest_matches_pointer(m: &ReleaseManifest, p: &ChannelPointer) -> bool {
m.version == p.release.version && m.tag == p.release.tag
&& m.source_commit == p.release.source_commit
&& m.release_workflow_identity == p.release.release_workflow_identity
} Try / catch
match verify_release_manifest(&bytes, &pointer) {
Err(e) if e.to_string().contains("does not match the signed channel pointer") => {
// refresh both artifacts from origin once, then retry
},
other => other,
} Prevention
- Publish pointer and manifest atomically
- Make per-version manifests immutable
- Use short CDN TTLs or content-addressed URLs
When it happens
Trigger: verify_release_manifest is called with a parsed ReleaseManifest where any of manifest.version, manifest.tag, manifest.source_commit, or manifest.release_workflow_identity differs from pointer.release's matching field.
Common situations: Cache/CDN serving a manifest for version N-1 while the pointer is for N; manifest regenerated (new commit) without re-issuing the signed pointer; a pointer replayed after a re-release of the same version; partial rollback where pointer and manifest updated at different times.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- opaque capsule asset directories cannot be symlinks: {}
- capsule archive entry '{requested}' is not a regular file
- capsule archive contains unsupported entry '{path}'
- capsule provenance envelope exceeds 64 KiB
- unsupported schema-version {} (expected {SCHEMA_VERSION})
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/6cb7f72ae28dc39a.
Report an issue: GitHub.