astrid-runtime/astrid · error
capsule source disappeared while preparing replacement: {}
Error message
capsule source disappeared while preparing replacement: {} What it means
After preparing the replacement runtime, the kernel verifies that the Capsule.toml still exists at the expected manifest path. If the source materialization vanished mid-preparation (e.g., a concurrent cleanup or build process removed it), it aborts the replacement rather than activating an incomplete runtime.
Source
Thrown at crates/astrid-kernel/src/lib.rs:2077
&bound.snapshot,
)?;
}
let principal_uid = self.runtime_principal_uid(system_runtime, principal, id)?;
let runtime_id =
self.capsules
.write()
.await
.reserve_runtime_id(id.clone(), artifact, actual_scope)?;
let mut capsule = self
.build_capsule_runtime(
manifest,
&runtime_dir,
(!system_runtime).then_some(principal),
runtime_id.clone(),
)
.await?;
if !manifest_path.exists() {
anyhow::bail!(
"capsule source disappeared while preparing replacement: {}",
manifest_path.display()
);
}
if let Err(error) = activate_and_wait_ready(id, capsule.as_mut()).await {
capsule.request_cancel();
if let Err(cleanup) = capsule.unload().await {
tracing::warn!(capsule_id = %id, error = %cleanup, "Failed to unload rejected replacement candidate");
}
return Err(error);
}
Ok(PreparedRuntimeReplacement {
capsule,
runtime_id,
principal_uid,
system_runtime,
})
}View on GitHub (pinned to affd8760f4)
Solutions
- Re-materialize the source directory and retry the replacement.
- Ensure no concurrent process deletes the workspace/runtime directory during replacement.
- Hold the capsule view/load lock around your replacement orchestration to serialize operations.
Example fix
// before
let prepared = kernel.prepare_replacement(id, &source_dir).await?;
activate(prepared).await?; // source may vanish in between
// after
if !source_dir.join("Capsule.toml").exists() {
rematerialize_source(&source_dir)?; // restore before replacing
}
let prepared = kernel.prepare_replacement(id, &source_dir).await?;
activate(prepared).await?; Defensive patterns
Strategy: retry
Validate before calling
let manifest_path = source_dir.join("Capsule.toml");
if !manifest_path.exists() {
return Err(anyhow!("source not ready: {}", manifest_path.display()));
} Try / catch
for attempt in 0..3 {
match kernel.replace_runtime(id, &source_dir).await {
Err(e) if e.to_string().contains("source disappeared") => {
rematerialize_source(&source_dir)?;
continue;
}
other => break other,
}
} Prevention
- Exclude runtime/workspace dirs from concurrent cleanup jobs.
- Serialize replacement operations per capsule with locks.
- Materialize sources on durable storage, not volatile temp paths.
When it happens
Trigger: Live replacement where the source/runtime directory (or its Capsule.toml) is deleted between preparation and activation — typically a concurrent workspace clean, temp-dir reclamation, or another replace operation overwriting the directory.
Common situations: A build watcher cleans the runtime directory during a hot reload; two replacement jobs race on the same capsule; the source_dir points at a disposable temp path that garbage collection removes.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- cannot replace capsule '{id}' for retiring principal '{princ
- workspace capsule manifest changed while it was being read:
- layout migration destination changed type: {}
- layout migration destination changed while inventoried: {}
- layout migration source changed type: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/9ab74b28ce7bbf6e.
Report an issue: GitHub.