astrid-runtime/astrid · error

capsule directory contains duplicate provenance

Error message

capsule directory contains duplicate provenance

What it means

Guard raised in collect_directory_records while walking the capsule content tree: two or more provenance entries for the same directory were found, meaning the provenance envelope records the same source more than once (e.g. duplicate include directives or repeated provenance sections). The walk aborts so the capsule's provenance attestation stays unambiguous. Called by verify_directory and recursively by itself.

Solutions

  1. Delete stale or extra provenance files so exactly one envelope remains
  2. Rebuild the capsule, which regenerates a single envelope
  3. Determine which envelope is legitimate before removing the others
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/astrid-build/src/artifact.rs:499 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

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

            let mut file = File::open(&resolved)?;
            records.push(hash_reader(normalized, metadata.len(), &mut file)?);
            continue;
        }
        if file_type.is_dir() {
            collect_directory_records(root, canonical_root, &path, records, envelope)?;
            continue;
        }
        if !file_type.is_file() {
            bail!(
                "capsule content contains a special file: {}",
                path.display()
            );
        }
        let relative = path.strip_prefix(root)?;
        let normalized = normalize_relative_path(relative)?;
        if normalized == PROVENANCE_FILE {
            if envelope.is_some() {
                bail!("capsule directory contains duplicate provenance");
            }
            *envelope = Some(std::fs::read(&path)?);
            continue;
        }
        let mut file = File::open(&path)?;
        let size = file.metadata()?.len();
        records.push(hash_reader(normalized, size, &mut file)?);
    }
    Ok(())
}

fn normalize_relative_path(path: &Path) -> anyhow::Result<String> {
    let mut parts = Vec::new();
    for component in path.components() {
        match component {
            Component::Normal(part) => parts.push(
                part.to_str()
                    .context("capsule paths must be UTF-8")?

View on GitHub (pinned to affd8760f4)