{"record":{"id":"9ab74b28ce7bbf6e","repo":"astrid-runtime/astrid","slug":"capsule-source-disappeared-while-preparing-replace","errorCode":null,"errorMessage":"capsule source disappeared while preparing replacement: {}","messagePattern":"capsule source disappeared while preparing replacement: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/lib.rs","lineNumber":2077,"sourceCode":"                &bound.snapshot,\n            )?;\n        }\n        let principal_uid = self.runtime_principal_uid(system_runtime, principal, id)?;\n        let runtime_id =\n            self.capsules\n                .write()\n                .await\n                .reserve_runtime_id(id.clone(), artifact, actual_scope)?;\n        let mut capsule = self\n            .build_capsule_runtime(\n                manifest,\n                &runtime_dir,\n                (!system_runtime).then_some(principal),\n                runtime_id.clone(),\n            )\n            .await?;\n        if !manifest_path.exists() {\n            anyhow::bail!(\n                \"capsule source disappeared while preparing replacement: {}\",\n                manifest_path.display()\n            );\n        }\n        if let Err(error) = activate_and_wait_ready(id, capsule.as_mut()).await {\n            capsule.request_cancel();\n            if let Err(cleanup) = capsule.unload().await {\n                tracing::warn!(capsule_id = %id, error = %cleanup, \"Failed to unload rejected replacement candidate\");\n            }\n            return Err(error);\n        }\n        Ok(PreparedRuntimeReplacement {\n            capsule,\n            runtime_id,\n            principal_uid,\n            system_runtime,\n        })\n    }","sourceCodeStart":2059,"sourceCodeEnd":2095,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/lib.rs#L2059-L2095","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet prepared = kernel.prepare_replacement(id, &source_dir).await?;\nactivate(prepared).await?; // source may vanish in between\n// after\nif !source_dir.join(\"Capsule.toml\").exists() {\n    rematerialize_source(&source_dir)?; // restore before replacing\n}\nlet prepared = kernel.prepare_replacement(id, &source_dir).await?;\nactivate(prepared).await?;","handlingStrategy":"retry","validationCode":"let manifest_path = source_dir.join(\"Capsule.toml\");\nif !manifest_path.exists() {\n    return Err(anyhow!(\"source not ready: {}\", manifest_path.display()));\n}","typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match kernel.replace_runtime(id, &source_dir).await {\n        Err(e) if e.to_string().contains(\"source disappeared\") => {\n            rematerialize_source(&source_dir)?;\n            continue;\n        }\n        other => break other,\n    }\n}","preventionTips":["Exclude runtime/workspace dirs from concurrent cleanup jobs.","Serialize replacement operations per capsule with locks.","Materialize sources on durable storage, not volatile temp paths."],"tags":["file-not-found","live-replacement","race-condition","filesystem"],"backgroundTag":"file-not-found","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}