astrid-runtime/astrid · error

WASM catalog entry is missing: bin/{hash}.wasm

Error message

WASM catalog entry is missing: bin/{hash}.wasm

What it means

Raised when describe() succeeded but returned None: there is no catalog entry named bin/{hash}.wasm under StateOwner::System. read_catalog_wasm uses this to distinguish 'backend failed' from 'entry genuinely absent' during catalog_wasm_hash integrity verification.

Source

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

        }
    }

    Ok(Some(WasmAddressed { hash, bytes }))
}

/// 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!(

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-install/re-publish the WASM so it is written into the system content catalog via content_address_wasm
  2. Confirm you are querying the same store/home the WASM was published to (StateOwner::System scope)
  3. Check whether a GC/cleanup process removed the catalog entry and restore it by re-publishing
  4. Verify the expected hash matches the artifact actually installed
Defensive patterns

Strategy: validation

Validate before calling

// check entry presence before hashing
let name = ContentName::new(format!("bin/{expected}.wasm"))?;
let present = storage.content().describe(&StateOwner::System, &name)
    .map_err(|e| anyhow::anyhow!(e))?.is_some();
if !present { anyhow::bail!("WASM {expected} not published; re-run install first"); }

Try / catch

match catalog_wasm_hash(&storage, &expected) {
    Err(e) if e.to_string().contains("catalog entry is missing") => {
        // republish from the trusted source artifact, then verify
        republish_wasm(&storage, &source_bytes)?;
        catalog_wasm_hash(&storage, &expected)
    }
    other => other,
}

Prevention

When it happens

Trigger: catalog_wasm_hash is called for an expected hash that was never published to the system catalog — e.g. the WASM was installed via the legacy bin-dir path (the else branch of content_address_wasm) instead of the catalog, or the catalog entry was deleted/compacted away.

Common situations: Install created before the content-catalog publish path existed (old layout on disk); another process ran garbage collection on the system content store; checking a hash from a different home/store than the one queried; typo'd or stale expected hash.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — 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/b5bddbcacf83fa1f. Report an issue: GitHub.