astrid-runtime/astrid · error
capsule identity mismatch: expected '{}', manifest declares
Error message
capsule identity mismatch: expected '{}', manifest declares '{id}' What it means
Inside install_from_local_path_internal, after loading the manifest, the parsed CapsuleId is compared against the optional ExpectedCapsuleIdentity passed by the caller. A mismatch means the directory being installed declares a different capsule name than the one the caller intended/approved, so the install aborts before any copy or store mutation. This duplicates the pre-check at the checked_authorized layer for callers that skip it.
Source
Thrown at crates/astrid-capsule-install/src/local.rs:576
Some(
workspace
.layout
.resolve(root)
.context("selected workspace state path is unsafe")?,
)
} else {
None
};
let manifest_path = source_dir.join("Capsule.toml");
if !manifest_path.exists() {
bail!("No Capsule.toml found in {}", source_dir.display());
}
let manifest = load_manifest(&manifest_path).context("failed to load Capsule manifest")?;
let id = CapsuleId::new(manifest.package.name.clone())?;
if let Some(expected) = expected
&& id != *expected.id
{
bail!(
"capsule identity mismatch: expected '{}', manifest declares '{id}'",
expected.id
);
}
let installed_version = manifest.package.version.clone();
if let Some(expected_version) = expected.and_then(|expected| expected.version)
&& installed_version != expected_version
{
bail!(
"capsule version mismatch for '{id}': expected '{expected_version}', manifest declares '{installed_version}'"
);
}
// Re-verify the exact source immediately before any target mutation. This
// closes the gap between pre-install approval and the transactional copy,
// including provenance-envelope swaps that leave content bytes unchanged.
let installed_authority =
authority_for_install_source(source_dir, &manifest, installed_authority)?;View on GitHub (pinned to affd8760f4)
Solutions
- Read package.name from the source Capsule.toml and make the expected id match exactly
- Correct package.name in the manifest if the directory is the source of truth
- Point source_dir at the directory of the intended capsule
- Drop the expected identity only if you truly want an unchecked install (not recommended for authorized flows)
Example fix
// before
let expected = ExpectedCapsuleIdentity { id: &CapsuleId::new("app-core")?, version: None };
// after
let manifest: Manifest = toml::from_str(&std::fs::read_to_string(src.join("Capsule.toml"))?)?;
let expected = ExpectedCapsuleIdentity { id: &CapsuleId::new(manifest.package.name.clone())?, version: None }; Defensive patterns
Strategy: validation
Validate before calling
fn check_identity(src: &Path, expected_id: &CapsuleId) -> anyhow::Result<()> {
let manifest: Manifest = toml::from_str(&std::fs::read_to_string(src.join("Capsule.toml"))?)?;
anyhow::ensure!(CapsuleId::new(manifest.package.name.clone())? == *expected_id, "id drift");
Ok(())
} Try / catch
if let Err(e) = install_from_local_path_internal(...) {
if e.to_string().contains("capsule identity mismatch") {
// reload manifest, resync expected identity, retry once
} else { return Err(e); }
} Prevention
- Single source of truth for capsule ids shared by approval and install code paths
- Re-derive expected identity from the manifest immediately before install
- Handle renames of package.name across the whole pipeline
- Avoid passing expected identities captured long before the install call
When it happens
Trigger: Passing expected = Some(ExpectedCapsuleIdentity { id, .. }) to install_from_local_path_internal (via any wrapper) while the Capsule.toml in source_dir declares a different package.name — e.g. expected 'app-core', manifest says 'app-core-utils'.
Common situations: Renamed capsule without updating callers; wrong source directory after a refactor; case-sensitive name mismatch; reusing an install routine parameterized by id but pointing at a template directory.
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
- capsule identity mismatch: expected '{expected}', manifest d
- capsule version mismatch for '{expected}': expected '{expect
- No Capsule.toml found in {}
- capsule version mismatch for '{id}': expected '{expected_ver
- capsule archive entry '{requested}' is not a regular file
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/d7f95e5c640c650b.
Report an issue: GitHub.