astrid-runtime/astrid · error

WASM catalog entry has no readable bytes: bin/{hash}.wasm

Error message

WASM catalog entry has no readable bytes: bin/{hash}.wasm

What it means

Raised when read_range succeeded but returned None (no bytes) even though the descriptor exists: the catalog entry bin/{hash}.wasm has metadata but zero readable content. read_catalog_wasm surfaces this so catalog_wasm_hash fails loudly instead of hashing empty bytes.

Source

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

/// 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-run the install so put_streaming_batch republishes the full WASM bytes into the catalog
  2. Check the WASM source file is non-empty before install (a 0-byte artifact produces an empty entry)
  3. Repair or reinitialize a corrupted content store and republish all catalog entries
  4. If using a custom content store, fix read_range so it returns an error rather than None for readable-data loss
Defensive patterns

Strategy: validation

Validate before calling

// reject empty artifacts before publishing
if wasm_bytes.is_empty() {
    anyhow::bail!("refusing to publish 0-byte WASM artifact");
}

Try / catch

match catalog_wasm_hash(&storage, &expected) {
    Err(e) if e.to_string().contains("no readable bytes") => {
        // entry exists but is empty: force a full republish
        storage.content().delete(&StateOwner::System, &name)?;
        republish_wasm(&storage, &source_bytes)?;
        catalog_wasm_hash(&storage, &expected)
    }
    other => other,
}

Prevention

When it happens

Trigger: catalog_wasm_hash -> read_catalog_wasm: describe() returns a descriptor, read_range(&StateOwner::System, &name, 0, descriptor.logical_bytes()) completes with Ok(None) — the entry exists in the index but holds no readable bytes.

Common situations: Interrupted streaming ingest that recorded the descriptor but not the data; empty/truncated blob files after a crash; storage backend returning empty reads silently (misbehaving custom backend); zero-byte WASM file published.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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