astrid-runtime/astrid · error
signed Distro member '{}' must resolve to a prebuilt .capsul
Error message
signed Distro member '{}' must resolve to a prebuilt .capsule archive What it means
resolve_signed_capsules requires every member of a signed Distro to resolve to a prebuilt .capsule archive. When a member's source is a relative path ('.') or absolute path ('/'), it is rejected outright because signed Distros only accept either local prebuilt archives or registry-resolvable names — path-style sources would bypass the signed-lock hash verification model.
Source
Thrown at crates/astrid-cli/src/commands/init_signed_source.rs:114
.ok_or_else(|| {
anyhow::anyhow!("selected capsule '{}' is not in signed lock", capsule.name)
})?;
let pinned_tag = signed.resolved_ref.as_deref().or(capsule.tag.as_deref());
let archive_path = staging.join(format!("{}.capsule", capsule.name));
if let Some(local_source) =
resolve_local_capsule_archive(&capsule.source, bundle.manifest_path.as_deref())
.with_context(|| format!("resolve signed capsule {}", capsule.name))?
{
std::fs::copy(&local_source, &archive_path).with_context(|| {
format!(
"copy signed capsule {} from {}",
capsule.name,
local_source.display()
)
})?;
} else {
if capsule.source.starts_with('.') || capsule.source.starts_with('/') {
bail!(
"signed Distro member '{}' must resolve to a prebuilt .capsule archive",
capsule.name
);
}
let _ = Some(
super::super::capsule::install::resolve_capsule_to_file(
&capsule.source,
(!capsule.version.is_empty()).then_some(capsule.version.as_str()),
pinned_tag,
Some(&capsule.name),
&archive_path,
)
.await?,
);
}
let bytes = std::fs::read(&archive_path)
.with_context(|| format!("read resolved capsule {}", capsule.name))?;
let actual = manifest_hash(&bytes);View on GitHub (pinned to affd8760f4)
Solutions
- Build the capsule first and reference the resulting prebuilt .capsule archive (path ending in .capsule) in Distro.toml.
- If the member should come from the registry, remove the leading '.' or '/' so the name is resolved via resolve_capsule_to_file.
- Verify each member's source field in Distro.toml: only registry names or prebuilt .capsule archive paths are allowed.
Example fix
// before (Distro.toml) [[capsule]] name = "my-tool" source = "./my-tool" // after [[capsule]] name = "my-tool" source = "./dist/my-tool.capsule"
Defensive patterns
Strategy: validation
Validate before calling
// pre-check Distro.toml member sources
for src in $(tomlq '.capsule[].source' Distro.toml); do
case "$src" in
.*|/*) [[ "$src" == *.capsule ]] || echo "INVALID signed member source: $src";;
esac
done Type guard
fn is_valid_signed_source(source: &str) -> bool {
!(source.starts_with('.') || source.starts_with('/')) || source.ends_with(".capsule")
} Try / catch
// rust
match resolve_signed_capsules(&capsules, &lock) {
Ok(members) => install(members),
Err(e) if e.to_string().contains("must resolve to a prebuilt .capsule archive") => {
eprintln!("build capsules first: astrid capsule build --all");
}
Err(e) => return Err(e),
} Prevention
- Always run the capsule build step before signing a Distro.
- Reference only registry names or prebuilt .capsule archives in signed Distro.toml.
- Lint Distro.toml for path-style sources in CI.
When it happens
Trigger: Calling resolve_signed_capsules with a Distro.toml member whose `source` field begins with '.' or '/', i.e. a relative or absolute filesystem path that is not a prebuilt .capsule archive.
Common situations: Hand-writing a Distro.toml and pointing a member at a source directory (e.g. source = "./my-capsule" or "/opt/capsules/foo") instead of a built .capsule file or a registry name; forgetting to run the capsule build step that produces the archive.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- invalid value for {capsule_id}.{key}: expected one of {}, go
- distro declared capsule '{expected}', but the checked instal
- MCP attach host is empty
- gateway.idle_shutdown_secs must be positive and representabl
- workspace capsule component must be relative: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/03b5f6c7e842d19b.
Report an issue: GitHub.