astrid-runtime/astrid · error

authority receipt has an empty capsule id

Error message

authority receipt has an empty capsule id

What it means

Raised by authority_capsule_id while building a package id from the capsule's authority.json receipt: the decoded InstalledAuthority has an empty capsule_id field. The library requires a non-empty capsule id to construct a valid package identity during publish_directory_package.

Solutions

  1. Open authority.json in the capsule source and set `capsule_id` to the capsule's actual identifier.
  2. Regenerate the authority receipt with the current toolchain instead of editing it by hand.
  3. If the receipt is unrecoverable, re-publish the capsule from its original source to produce a fresh receipt.

Example fix

// before: authority.json
{ "capsule_id": "" }

// after
{ "capsule_id": "my-capsule-0.1.0" }
Defensive patterns

Strategy: validation

Validate before calling

fn check_authority(authority_json: &[u8]) -> Result<(), String> {
    let v: serde_json::Value = serde_json::from_slice(authority_json).map_err(|e| e.to_string())?;
    match v["capsule_id"].as_str() {
        Some(id) if !id.is_empty() => Ok(()),
        _ => Err("capsule_id missing or empty".into()),
    }
}

Type guard

fn has_capsule_id(v: &serde_json::Value) -> bool {
    v.get("capsule_id").and_then(|x| x.as_str()).map_or(false, |s| !s.is_empty())
}

Try / catch

match publish_directory_package(...) {
    Err(e) if e.to_string().contains("empty capsule id") => { regenerate_authority_receipt()?; retry(); }
    other => other?,
}

Prevention

When it happens

Trigger: Publishing a directory/legacy package whose authority.json decodes successfully but has `capsule_id: ""` — e.g. a hand-written or truncated receipt, or an older receipt format missing the field defaulting to an empty string.

Common situations: Manually authored authority.json in a capsule directory; receipts damaged by truncation or bad merges; receipts generated by an old tool version that did not set capsule_id.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at crates/astrid-capsule-install/src/storage.rs:738

    let value: toml::Value = toml::from_str(&manifest).context("parse capsule manifest")?;
    let id = value
        .get("package")
        .and_then(|package| package.get("name"))
        .and_then(toml::Value::as_str)
        .ok_or_else(|| anyhow::anyhow!("Capsule.toml has no package.name"))?;
    let version = value
        .get("package")
        .and_then(|package| package.get("version"))
        .and_then(toml::Value::as_str)
        .ok_or_else(|| anyhow::anyhow!("Capsule.toml has no package.version"))?;
    Ok((id.to_owned(), version.to_owned()))
}

fn authority_capsule_id(authority: &[u8]) -> anyhow::Result<String> {
    let authority: InstalledAuthority =
        serde_json::from_slice(authority).context("decode authority receipt for package id")?;
    if authority.capsule_id.is_empty() {
        bail!("authority receipt has an empty capsule id");
    }
    Ok(authority.capsule_id)
}

/// Build a deterministic gzip/tar package from a checked directory.
pub fn canonical_capsule_archive(source_dir: &Path) -> anyhow::Result<Vec<u8>> {
    let mut entries = Vec::new();
    collect_entries(source_dir, source_dir, &mut entries)?;
    if !entries
        .iter()
        .any(|(path, _)| path == Path::new("Capsule.toml"))
    {
        bail!("capsule source has no Capsule.toml");
    }
    entries.sort_by(|left, right| left.0.cmp(&right.0));

    let output = Vec::new();
    let encoder = GzEncoder::new(output, Compression::default());

View on GitHub (pinned to affd8760f4)