astrid-runtime/astrid · error

capsule provenance envelope exceeds 64 KiB

Error message

capsule provenance envelope exceeds 64 KiB

What it means

Finally, verify_release_manifest requires the manifest's targets table to be byte-for-byte equal to the targets embedded in the signed channel pointer (after validate_targets passed on the manifest itself). This error means the set of platform targets — their asset URLs/digests — differs between the manifest and the signed pointer, so the client cannot trust which artifacts belong to this release.

Source

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

    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;
        }
        records.push(hash_reader(path, entry.size(), &mut entry)?);
    }
    Ok((records, envelope))
}

fn normalized_entry_path<R: Read>(entry: &tar::Entry<'_, R>) -> anyhow::Result<String> {
    let path = entry.path().context("invalid capsule archive path")?;
    let mut parts = Vec::new();
    for component in path.components() {
        match component {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-sign the channel pointer with the exact same targets table as the current manifest (or vice versa: publish the manifest matching the pointer's targets).
  2. Regenerate both artifacts together in the release pipeline so targets are captured once and reused.
  3. If a target was legitimately added post-release, cut a new generation of the pointer including it.

Example fix

# before: pointer targets
[[targets]]
triple = "x86_64-unknown-linux-gnu"
# manifest also has aarch64-apple-darwin -> mismatch
# after: regenerate pointer including all manifest targets
pointer.targets = manifest.targets.clone();
Defensive patterns

Strategy: validation

Validate before calling

fn targets_match(m: &ReleaseManifest, p: &ChannelPointer) -> bool {
    m.targets == p.targets
}

Try / catch

match verify_release_manifest(&bytes, &pointer) {
    Err(e) if e.to_string().contains("targets do not match") => eprintln!("re-fetch both artifacts or re-sign pointer with current targets"),
    other => other,
}

Prevention

When it happens

Trigger: verify_release_manifest (via resolve_signed_channel or workflow_identity_and_metadata_digest_are_exact) finds manifest.targets != pointer.targets after validate_targets(&manifest.targets, &manifest.version) succeeded.

Common situations: A new platform target added to the manifest but the pointer was signed earlier without it; a target's asset hash or URL changed on a re-upload; pointer generated from a template with a default target list; partial rollback of one target.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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