astrid-runtime/astrid · error

read materialized capsule authority: {error:#}

Error message

read materialized capsule authority: {error:#}

What it means

During verification of a published capsule materialization, the kernel re-reads the projected authority.json file with read_projection_file_nofollow and wraps any I/O failure with this message. The library throws it because authority.json is the durable record of the capsule's approved authority; if it cannot be read, the kernel cannot prove the materialized capsule does not exceed its installed authority. As with the sibling errors, this is an I/O wrapper — a content mismatch yields the distinct 'durable capsule authority bytes do not match materialization' error.

Source

Thrown at crates/astrid-kernel/src/capsule_materialization.rs:49

            anyhow::bail!("materialized capsule snapshot differs from the caller's publication");
        }
        if verified.manifest().package.name != manifest.package.name
            || verified.manifest().package.version != manifest.package.version
        {
            anyhow::bail!("materialized capsule manifest differs from durable registry");
        }
        let manifest_bytes = Self::read_projection_file_nofollow(&dir.join("Capsule.toml"))
            .map_err(|error| anyhow::anyhow!("read materialized capsule manifest: {error:#}"))?;
        if manifest_bytes != verified.manifest_bytes() {
            anyhow::bail!("durable capsule manifest bytes do not match materialization");
        }
        let metadata_bytes = Self::read_projection_file_nofollow(&dir.join("meta.json"))
            .map_err(|error| anyhow::anyhow!("read materialized capsule metadata: {error:#}"))?;
        if metadata_bytes != verified.metadata_bytes() {
            anyhow::bail!("durable capsule metadata does not match materialization");
        }
        let authority_bytes = Self::read_projection_file_nofollow(&dir.join("authority.json"))
            .map_err(|error| anyhow::anyhow!("read materialized capsule authority: {error:#}"))?;
        if authority_bytes != verified.snapshot().package().authority {
            anyhow::bail!("durable capsule authority bytes do not match materialization");
        }
        let mut expected_files = verified
            .archive_entries()
            .map(|(path, bytes)| (path.to_owned(), bytes.to_vec()))
            .collect::<std::collections::BTreeMap<_, _>>();
        expected_files.insert(
            "Capsule.toml".to_owned(),
            verified.manifest_bytes().to_vec(),
        );
        expected_files.insert("meta.json".to_owned(), verified.metadata_bytes().to_vec());
        expected_files.insert(
            "authority.json".to_owned(),
            verified.snapshot().package().authority.clone(),
        );
        let actual = Self::inventory_projection_files(dir)?;
        if actual.files

View on GitHub (pinned to affd8760f4)

Solutions

  1. Remove the stale/partial materialization and re-materialize: call repair_published_materialization or ensure_published_materialization so the projection is rebuilt from the durable snapshot.
  2. Verify authority.json exists, is a regular file, and is readable: ls -la <dir>/authority.json; restore permissions if needed (chown/chmod).
  3. Ensure nothing concurrently deletes or replaces the cache directory during verification (hold the activation lock / avoid parallel capsule operations).
  4. Re-publish the capsule if the durable registry copy itself is suspect.

Example fix

// before: confirming a possibly torn cache
kernel.confirm_published_materialization(&dir, &principal, &manifest, &snapshot)?;

// after: let repair rebuild the projection when verification fails
if kernel.confirm_published_materialization(&dir, &principal, &manifest, &snapshot).is_err() {
    kernel.ensure_published_materialization(&dir, &principal, &manifest, &snapshot)?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn authority_projection_readable(dir: &std::path::Path) -> Result<(), String> {
    let p = dir.join("authority.json");
    let md = std::fs::symlink_metadata(&p)
        .map_err(|e| format!("authority.json unreadable: {e}"))?;
    if md.file_type().is_symlink() { return Err("authority.json is a symlink".into()); }
    if !md.is_file() { return Err("authority.json is not a regular file".into()); }
    std::fs::File::open(&p).map_err(|e| format!("authority.json open failed: {e}"))?;
    Ok(())
}

Type guard

fn has_regular_file(dir: &std::path::Path, name: &str) -> bool {
    std::fs::symlink_metadata(dir.join(name))
        .map(|md| md.is_file())
        .unwrap_or(false)
}

Try / catch

if let Err(e) = kernel.confirm_published_materialization(&dir, &principal, &manifest, &snapshot) {
    if e.to_string().contains("read materialized capsule authority") {
        let _ = std::fs::remove_dir_all(&dir);
        kernel.ensure_published_materialization(&dir, &principal, &manifest, &snapshot)?;
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: verify_published_materialization (via repair_published_materialization, confirm_published_materialization, or verify_registry_materialization) reaches the authority.json check while <materialization_dir>/authority.json is missing, unreadable, is a symlink (nofollow open refuses), or is not readable by the current user/UID.

Common situations: Interrupted materialization left authority.json absent; the cache directory was partially cleaned by a temp cleaner or manual rm; a symlink or hardened permissions block the read; concurrent repair races removed the directory between checks; network filesystem hiccup.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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