astrid-runtime/astrid · error

capsule archive contains duplicate entry '{requested}'

Error message

capsule archive contains duplicate entry '{requested}'

What it means

Each signed pointer must pin the exact GitHub Actions release workflow that produced the version: 'https://github.com/<REPOSITORY>/.github/workflows/release.yml@refs/tags/v<version>'. This ensure! fails when release_workflow_identity deviates from that canonical URL, blocking pointers whose provenance cannot be tied to the official release workflow.

Source

Thrown at crates/astrid-build/src/artifact.rs:224

///
/// Fails when the archive is malformed, contains duplicate matching entries,
/// or the requested entry is absent or not UTF-8.
pub fn read_archive_text(archive_path: &Path, requested: &str) -> anyhow::Result<String> {
    let file = File::open(archive_path)
        .with_context(|| format!("failed to open {}", archive_path.display()))?;
    let mut archive = tar::Archive::new(GzDecoder::new(file));
    let mut found = None;
    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 path != requested {
            continue;
        }
        if found.is_some() {
            bail!("capsule archive contains duplicate entry '{requested}'");
        }
        if !entry.header().entry_type().is_file() {
            bail!("capsule archive entry '{requested}' is not a regular file");
        }
        let mut bytes = Vec::new();
        entry.read_to_end(&mut bytes)?;
        found =
            Some(String::from_utf8(bytes).with_context(|| {
                format!("capsule archive entry '{requested}' is not valid UTF-8")
            })?);
    }
    found.with_context(|| format!("capsule archive is missing '{requested}'"))
}

fn read_archive(archive_path: &Path) -> anyhow::Result<(Vec<ContentRecord>, Option<Vec<u8>>)> {
    let file = File::open(archive_path)
        .with_context(|| format!("failed to open {}", archive_path.display()))?;
    read_archive_reader(GzDecoder::new(file))

View on GitHub (pinned to affd8760f4)

Solutions

  1. Set release_workflow_identity to exactly format!("https://github.com/{REPOSITORY}/.github/workflows/release.yml@refs/tags/v{version}").
  2. If the repository or workflow was renamed, regenerate the pointer with current tooling (the check will only pass for the canonical name).
  3. Re-sign and redistribute the corrected pointer.

Example fix

# before
release_workflow_identity = "https://github.com/acme/astrid/.github/workflows/publish.yml@main"
# after
release_workflow_identity = "https://github.com/acme/astrid/.github/workflows/release.yml@refs/tags/v1.2.3"
Defensive patterns

Strategy: validation

Validate before calling

fn workflow_identity_ok(repo: &str, version: &str, identity: &str) -> bool {
    identity == format!("https://github.com/{repo}/.github/workflows/release.yml@refs/tags/v{version}")
}

Try / catch

if let Err(e) = parse_channel(&bytes, channel, now) {
    if e.to_string().contains("workflow identity is invalid") { eprintln!("use canonical release.yml@refs/tags/v<version>"); }
    return Err(e.into());
}

Prevention

When it happens

Trigger: validate_pointer (via parse_channel or enforce_continuity) sees release.release_workflow_identity differing from the repository/workflow/tag-ref template built from REPOSITORY and the pointer's version.

Common situations: Repository renamed or forked so the URL host/org changed; workflow file renamed (e.g. release.yml to publish.yml); ref written as a SHA or a branch instead of refs/tags/v<version>; pointer copied from another product's channel.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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