astrid-runtime/astrid · error

read WASM from system catalog

Error message

read WASM from system catalog

What it means

Wraps a storage error from content().read_range() when reading back the full byte range of a WASM catalog entry after a successful describe(). The descriptor exists but actually reading the bytes failed, so catalog_wasm_hash cannot compute the integrity digest.

Source

Thrown at crates/astrid-capsule-install/src/wasm.rs:121

}

/// Read one verified executable from the system-owned content catalog.
pub(crate) fn read_catalog_wasm(
    storage: &RuntimePrincipalStore,
    hash: &str,
) -> anyhow::Result<Vec<u8>> {
    let name = ContentName::new(format!("bin/{hash}.wasm"))
        .context("construct system WASM catalog name")?;
    let descriptor = storage
        .content()
        .describe(&StateOwner::System, &name)
        .map_err(|error| anyhow::anyhow!(error))
        .context("describe WASM in system catalog")?
        .ok_or_else(|| anyhow::anyhow!("WASM catalog entry is missing: bin/{hash}.wasm"))?;
    storage
        .content()
        .read_range(&StateOwner::System, &name, 0, descriptor.logical_bytes())
        .map_err(|error| anyhow::anyhow!(error))
        .context("read WASM from system catalog")?
        .ok_or_else(|| anyhow::anyhow!("WASM catalog entry has no readable bytes: bin/{hash}.wasm"))
}

/// Verify that the system catalog entry for `expected` exists and hashes to
/// its content-addressed name.
pub fn catalog_wasm_hash(
    storage: &RuntimePrincipalStore,
    expected: &str,
) -> anyhow::Result<String> {
    let actual = blake3::hash(&read_catalog_wasm(storage, expected)?)
        .to_hex()
        .to_string();
    anyhow::ensure!(
        actual == expected,
        "installed WASM integrity check failed: expected BLAKE3 {expected}, got {actual}"
    );
    Ok(actual)

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-publish the WASM into the catalog (re-run the install) to rewrite the missing/truncated blob
  2. Inspect the wrapped storage error for the concrete filesystem/backend cause
  3. Check the content store for orphaned descriptors and prune or repair them
  4. Verify no concurrent GC/compaction is running while reads are in flight
Defensive patterns

Strategy: retry

Validate before calling

// sanity: descriptor and blob must both be readable
let d = storage.content().describe(&StateOwner::System, &name)?.ok_or("missing")?;
storage.content().read_range(&StateOwner::System, &name, 0, d.logical_bytes())?
    .ok_or("blob unreadable")?;

Try / catch

match catalog_wasm_hash(&storage, &expected) {
    Err(e) if e.to_string().contains("read WASM from system catalog") => {
        // blob missing/truncated: republish and re-verify once
        republish_wasm(&storage, &source_bytes)?;
        catalog_wasm_hash(&storage, &expected)
    }
    other => other,
}

Prevention

When it happens

Trigger: catalog_wasm_hash -> read_catalog_wasm: describe(&StateOwner::System, name) returns Some(descriptor), then read_range(&StateOwner::System, &name, 0, descriptor.logical_bytes()) returns Err.

Common situations: Underlying blob file deleted or truncated while the descriptor still exists (partial GC, interrupted write); filesystem read/permission errors; corrupt content-store index pointing at a missing chunk; descriptor reporting logical_bytes beyond what is physically stored.

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/89188e120e3a1876. Report an issue: GitHub.