astrid-runtime/astrid · warning
runtime tree changed while packed admission was in progress
Error message
runtime tree changed while packed admission was in progress
What it means
During packed admission, the kernel scans the runtime tree before and after admitting it, and requires the receipt digest to be stable. If `RuntimeTreeReceipt::from_entries` computed from the pre-scan does not match the post-scan entries, the tree was mutated concurrently and the operation aborts with WouldBlock instead of persisting a torn view.
Solutions
- Retry the admission operation once the tree is quiescent (WouldBlock signals a safe retry)
- Close other running instances of the app before admitting
- Pause file sync/indexing tools that touch the home directory
- Serialize home-mutating operations through a single process/lock
Defensive patterns
Strategy: retry
Try / catch
match err.downcast_ref::<io::Error>() {
Some(e) if e.kind() == io::ErrorKind::WouldBlock => {
std::thread::sleep(Duration::from_millis(200));
retry_admit()?; // safe: nothing was persisted
}
_ => return Err(err),
} Prevention
- Ensure single-writer access to the home (one app instance, one CLI invocation)
- Exclude the home from live sync/indexing tools
- Acquire your own lock around home-mutating operations
When it happens
Trigger: `admit_blocking` (called via `admit`) observes `!before.matches_entries(&after)` — files were added/removed/modified in the runtime tree between the two scans, including the test-only source mutation hook.
Common situations: Another app instance or CLI command writing to the home concurrently; a sync tool changing files mid-admission; the user moving files while the app starts up.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- capsule disappeared during durable contracts scan
- corpus input changed while its baseline snapshot was…
- durable capsule package
- mountpoint was concurrently registered
- shutdown stage gateway.startup_identity: startup generation…
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/c6a748947cb17efe.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/runtime_tree_admit.rs:101
fn admit_blocking(home: &AstridHome, store: &RuntimePrincipalStore) -> io::Result<()> {
let entries = scan(store, home.root())?;
let receipt_path = home.migrations_dir().join(RECEIPT_NAME);
if let Some(receipt) = read_receipt(&receipt_path)?
&& receipt.matches_entries(&entries)
&& catalog_contains_entries(store, &entries)?
&& catalog_contains_receipt(store, &receipt_path)?
{
return Ok(());
}
store
.admit_runtime_tree(home.root())
.map_err(storage_error)?;
#[cfg(test)]
run_source_mutation_hook(home)?;
let after = scan(store, home.root())?;
if !RuntimeTreeReceipt::from_entries(&entries).matches_entries(&after) {
return Err(io::Error::new(
io::ErrorKind::WouldBlock,
"runtime tree changed while packed admission was in progress",
));
}
let receipt = RuntimeTreeReceipt::from_entries(&after);
let bytes = serde_json::to_vec(&receipt).map_err(io::Error::other)?;
astrid_core::platform_fs::ensure_private_directory(&home.migrations_dir())?;
astrid_core::platform_fs::atomic_write_private_file(&receipt_path, &bytes)?;
admit_receipt(store, &receipt_path)?;
store
.establish_runtime_projection_receipt(home)
.map_err(storage_error)
}
fn admit_receipt(store: &RuntimePrincipalStore, receipt_path: &Path) -> io::Result<()> {
let name = ContentName::new(RECEIPT_RELATIVE_PATH.to_owned()).map_err(io::Error::other)?;
let bytes = fs::metadata(receipt_path)?.len();
storeView on GitHub (pinned to affd8760f4)