astrid-runtime/astrid · error

replacement manifest id

Error message

replacement manifest id '{}' does not match running capsule '{id}'

What it means

Before performing a live replacement, the kernel loads the Capsule.toml from the prepared source directory and checks that its `package.name` equals the id of the running capsule being replaced. A mismatch means the source materialization belongs to a different capsule and replacing would silently swap in unrelated code.

Solutions

  1. Make the Capsule.toml `package.name` match the id passed to the replacement call.
  2. Pass the correct source_dir belonging to the running capsule.
  3. If the capsule was renamed, unload the old capsule and load the new one instead of a live replacement.

Example fix

# before (Capsule.toml)
[package]
name = "my-capsule-v2"
# after
[package]
name = "my-capsule"  # must match the running capsule id
Defensive patterns

Strategy: validation

Validate before calling

let manifest = astrid_capsule::discovery::load_manifest(&source_dir.join("Capsule.toml"))?;
assert_eq!(manifest.package.name, id.as_str(), "replacement source belongs to a different capsule");

Try / catch

if let Err(e) = kernel.prepare_replacement(id, &source_dir).await {
    if e.to_string().contains("does not match running capsule") {
        return Err(anyhow!("check source_dir: {} points at a different capsule", source_dir.display()));
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Calling the replace/reload-preparation API for capsule `{id}` with a `source_dir` whose Capsule.toml declares a different `package.name` (e.g., the directory was repointed at another capsule's checkout).

Common situations: Pointing the replacement path at the wrong workspace member; renaming a capsule in Capsule.toml while the kernel still references the old id; copying the wrong runtime directory over the source of truth.

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


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

Appendix: source

Thrown at crates/astrid-kernel/src/lib.rs:2006

        capsule_adversarial_tests::record_workspace_source(&capsule_name, &ctx.workspace_source);
        capsule.load(&ctx).await?;
        Ok(capsule)
    }

    #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
    async fn prepare_runtime_replacement(
        &self,
        id: &astrid_capsule_types::CapsuleId,
        source_dir: &Path,
        principal: &PrincipalId,
        expected_scope: astrid_capsule::registry::RuntimeScope,
    ) -> Result<PreparedRuntimeReplacement, anyhow::Error> {
        self.verify_workspace_capsule_tree(source_dir)?;
        let manifest_path = source_dir.join("Capsule.toml");
        let manifest = astrid_capsule::discovery::load_manifest(&manifest_path)
            .map_err(|error| anyhow::anyhow!(error))?;
        if manifest.package.name != id.as_str() {
            anyhow::bail!(
                "replacement manifest id '{}' does not match running capsule '{id}'",
                manifest.package.name
            );
        }
        let bound = self.capture_bound_materialization(
            source_dir,
            principal,
            &manifest,
            "replacement source",
        )?;
        let runtime_dir = bound.as_ref().map_or_else(
            || source_dir.to_path_buf(),
            |bound| bound.runtime_dir.clone(),
        );
        let manifest = bound
            .as_ref()
            .map_or_else(|| manifest, |bound| bound.manifest.clone());
        let manifest_path = runtime_dir.join("Capsule.toml");

View on GitHub (pinned to affd8760f4)