{"record":{"id":"697c5e25b4415762","repo":"astrid-runtime/astrid","slug":"remove-stale-capsule-materialization-error","errorCode":null,"errorMessage":"remove stale capsule materialization: {error}","messagePattern":"remove stale capsule materialization: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/capsule_materialization.rs","lineNumber":200,"sourceCode":"            Err(error) => return Err(anyhow::anyhow!(\"inspect capsule materialization: {error}\")),\n        };\n        if let Some(metadata) = target_metadata {\n            if metadata.file_type().is_symlink() || !metadata.is_dir() {\n                anyhow::bail!(\"capsule materialization target is redirected or not a directory\");\n            }\n            if let Ok(bound_manifest) =\n                astrid_capsule::discovery::load_manifest(&target.join(\"Capsule.toml\"))\n                && self\n                    .verify_published_materialization(target, principal, &bound_manifest, snapshot)\n                    .is_ok()\n            {\n                return Ok(bound_manifest);\n            }\n            astrid_core::platform_fs::verify_no_redirects(target).map_err(|error| {\n                anyhow::anyhow!(\"capsule materialization target is redirected: {error}\")\n            })?;\n            std::fs::remove_dir_all(target).map_err(|error| {\n                anyhow::anyhow!(\"remove stale capsule materialization: {error}\")\n            })?;\n        }\n        astrid_capsule_install::materialize_capsule_package(snapshot.package(), target)\n            .map_err(|error| anyhow::anyhow!(\"materialize durable capsule package: {error:#}\"))?;\n        let bound_manifest = astrid_capsule::discovery::load_manifest(&target.join(\"Capsule.toml\"))\n            .map_err(|error| anyhow::anyhow!(error))?;\n        self.verify_published_materialization(target, principal, &bound_manifest, snapshot)?;\n        Ok(bound_manifest)\n    }\n\n    /// Recheck the immutable publication after taking activation locks.\n    #[cfg(not(all(target_arch = \"wasm32\", target_os = \"unknown\")))]\n    pub(crate) fn confirm_published_materialization(\n        &self,\n        dir: &Path,\n        principal: &astrid_core::principal::PrincipalId,\n        manifest: &astrid_capsule_types::manifest::CapsuleManifest,\n        snapshot: &astrid_storage::CapsulePackageSnapshot,","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/capsule_materialization.rs#L182-L218","documentation":"Thrown by `repair_published_materialization` when the stale materialization directory passed the redirect check but `std::fs::remove_dir_all(target)` fails. The library needs to delete the stale cache directory before re-materializing from the package snapshot; if the OS refuses the delete (permissions, busy/open files, read-only filesystem), repair cannot proceed and the underlying io::Error is wrapped verbatim.","triggerScenarios":"Calling `ensure_published_materialization`/`capture_bound_materialization` where the target exists, is a real directory with a stale/unverifiable manifest, contains no redirects, but `remove_dir_all` returns an io::Error (e.g. EACCES, EBUSY, EROFS, EPERM on immutable files).","commonSituations":"Running the tool as a non-root user while the cache directory is owned by root (e.g. created by a sudo install); another process (editor, dev server, container) holds files open inside the cache on Windows/NFS; the cache lives on a read-only mount or Docker volume mounted `:ro`; file immutability flags (chattr +i) set on cache entries.","solutions":["Delete the target directory manually with sufficient privileges (e.g. `sudo rm -rf <target>` or fixing ownership with `chown -R`), then re-run the operation.","Close processes holding files open inside the target directory (dev servers, watchers, containers) and retry.","If the cache is on a read-only mount, remount it read/write or relocate the cache directory to writable storage.","Check and clear immutable attributes (`chattr -i`) or ACLs on the cache entries."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"use std::path::Path;\n\nfn target_is_deletable(target: &Path) -> Result<(), String> {\n    let md = std::fs::symlink_metadata(target)\n        .map_err(|e| format!(\"target missing/unreadable: {e}\"))?;\n    if !md.is_dir() || md.file_type().is_symlink() {\n        return Err(\"target is not a real directory\".into());\n    }\n    // Probe write access to the directory (a directory can be removed only\n    // if its parent is writable, and emptied only if children are writable).\n    let probe = target.join(\".astrid-delete-probe\");\n    std::fs::File::create(&probe)\n        .and_then(|_| std::fs::remove_file(&probe))\n        .map_err(|e| format!(\"cache dir not writable by current user: {e}\"))\n}","typeGuard":"fn can_write_directory(dir: &Path) -> bool {\n    let probe = dir.join(\".write-probe\");\n    let ok = std::fs::File::create(&probe).is_ok();\n    let _ = std::fs::remove_file(&probe);\n    ok\n}","tryCatchPattern":"match ensure_published_materialization(&target, &principal, &manifest, &snapshot) {\n    Ok(manifest) => {/* use bound manifest */}\n    Err(e) if e.to_string().contains(\"remove stale capsule materialization\") => {\n        eprintln!(\"cache dir could not be deleted: {e:#}\");\n        eprintln!(\"hint: check ownership/permissions, close processes using it, or run: rm -rf {}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Run all operations against the cache with the same user that created it; avoid mixing sudo and non-sudo runs.","Point the cache at a writable local volume; never mount it read-only.","Stop watchers/dev servers/containers that hold files open in the cache before repairing.","Avoid immutable flags (chattr +i) or restrictive ACLs on cache contents."],"tags":["filesystem","permissions","cache","delete-failed"],"backgroundTag":"file-write-failed","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}