astrid-runtime/astrid · error
capsule '{}' changed while activation was in progress
Error message
capsule '{}' changed while activation was in progress What it means
This error means the published capsule snapshot on disk no longer matches the snapshot the kernel captured when materialization/activation began. The library throws it in confirm_published_materialization as a compare-and-swap style consistency check: between reading the snapshot and confirming activation, the durable published state changed, so activating against the stale snapshot would be unsafe. It is deliberately a hard bail to prevent activating a capsule based on outdated materialized state.
Source
Thrown at crates/astrid-kernel/src/capsule_materialization.rs:222
.map_err(|error| anyhow::anyhow!("materialize durable capsule package: {error:#}"))?;
let bound_manifest = astrid_capsule::discovery::load_manifest(&target.join("Capsule.toml"))
.map_err(|error| anyhow::anyhow!(error))?;
self.verify_published_materialization(target, principal, &bound_manifest, snapshot)?;
Ok(bound_manifest)
}
/// Recheck the immutable publication after taking activation locks.
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub(crate) fn confirm_published_materialization(
&self,
dir: &Path,
principal: &astrid_core::principal::PrincipalId,
manifest: &astrid_capsule_types::manifest::CapsuleManifest,
snapshot: &astrid_storage::CapsulePackageSnapshot,
) -> anyhow::Result<()> {
let current = self.published_capsule_snapshot(principal, manifest)?;
if current.as_ref() != Some(snapshot) {
anyhow::bail!(
"capsule '{}' changed while activation was in progress",
manifest.package.name
);
}
self.verify_published_materialization(dir, principal, manifest, snapshot)
}
}
View on GitHub (pinned to affd8760f4)
Solutions
- Re-read the capsule snapshot (load_capsule / fetch latest) and retry the materialization with the fresh snapshot
- Ensure only one activation per capsule runs at a time (serialize load_capsule / prepare_runtime_replacement calls with a lock)
- If a mutable tag was republished, pin the capsule to an immutable digest and re-run activation
- Check for background registry-sync jobs or other kernels writing to the published capsule location and stop them during deploys
Example fix
// before: reusing a snapshot captured earlier
let snapshot = cached_snapshot.clone();
kernel.confirm_published_materialization(&principal, &manifest, &snapshot).await?;
// after: re-read the current snapshot, retry on concurrent change
let snapshot = kernel.published_capsule_snapshot(&principal, &manifest)
.await?
.ok_or_else(|| anyhow::anyhow!("capsule not published"))?;
match kernel.confirm_published_materialization(&principal, &manifest, &snapshot).await {
Ok(()) => {},
Err(e) if e.to_string().contains("changed while activation") => {
// serialize with a lock and retry once with fresh state
let _guard = activation_lock.lock().await;
let fresh = kernel.published_capsule_snapshot(&principal, &manifest).await?;
kernel.confirm_published_materialization(&principal, &manifest, &fresh).await?;
}
Err(e) => return Err(e),
} Defensive patterns
Strategy: retry
Validate before calling
let current = kernel.published_capsule_snapshot(&principal, &manifest).await?;
if current.as_ref() != Some(&snapshot) {
// refresh snapshot before calling confirm_published_materialization
} Try / catch
match result {
Err(e) if e.to_string().contains("changed while activation was in progress") => retry_with_fresh_snapshot().await?,
other => other?,
} Prevention
- Serialize activations per capsule with a mutex/lock
- Pin capsules to immutable digests instead of mutable tags
- Avoid republishing capsule tags while deployments are in flight
- Re-read the snapshot immediately before confirming activation
When it happens
Trigger: confirm_published_materialization is called (directly via load_capsule, or via prepare_runtime_replacement); it re-reads published_capsule_snapshot(principal, manifest) and the result differs from the snapshot passed in — e.g. a concurrent republish/overwrite of the same capsule, a registry sync updating the digest, or a second activation racing the first.
Common situations: Two processes or kernels activating the same capsule version concurrently; an operator re-publishing a capsule tag (mutable tag) while a deployment is in flight; a CI pipeline pushing a new digest for the same package mid-deploy; stale cached snapshot reused after the registry was updated.
Related errors
- projected file changed while read: {}
- an incomplete capsule authority update exists at {}; remove
- quarantined capsule authority bytes changed: {}
- leftover capsule authority receipt changed before retirement
- capsule {} disappeared during durable contracts scan
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/032d61e6733140fc.
Report an issue: GitHub.