{"record":{"id":"d9c9a2a66fb714cf","repo":"astrid-runtime/astrid","slug":"materialize-durable-capsule-package-error","errorCode":null,"errorMessage":"materialize durable capsule package: {error:#}","messagePattern":"materialize durable capsule package: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/capsule_materialization.rs","lineNumber":204,"sourceCode":"                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,\n    ) -> anyhow::Result<()> {\n        let current = self.published_capsule_snapshot(principal, manifest)?;\n        if current.as_ref() != Some(snapshot) {\n            anyhow::bail!(","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/capsule_materialization.rs#L186-L222","documentation":"Thrown when the actual materialization step — `astrid_capsule_install::materialize_capsule_package(snapshot.package(), target)` — fails after the stale directory was cleared. The package contents from the storage snapshot could not be written into the target directory, and the full error chain (`{error:#}`) is preserved. This is the core 'unpack/install of the capsule package failed' error of the repair path.","triggerScenarios":"Any failure inside `materialize_capsule_package`: disk full during extraction, permission denied creating files in the (recreated) target, corrupted or incomplete package snapshot data from the storage layer, or the target becoming unwritable between the delete and the materialize call.","commonSituations":"Disk quota or no-space-left conditions on the cache volume; concurrent runs of the tool racing to materialize the same target; corrupted capsule package in the storage backend after an interrupted upload; running under a sandbox (CI container) that forbids writing to the cache path; antivirus/EDR blocking rapid file creation.","solutions":["Read the inner error chain (`{error:#}` in the message) to identify the root cause (permissions vs disk space vs corrupt package), then fix that specifically.","Free disk space / raise the quota on the volume holding the materialization target and retry.","If the stored package is corrupted, re-publish or re-fetch the capsule package snapshot so the storage layer holds valid data.","Ensure the parent directory of the target exists and is writable by the current user before invoking the operation.","Serialize concurrent invocations (locks) or use distinct target directories to avoid two processes materializing into the same path."],"exampleFix":"// before: cache dir on a tiny tmpfs\nexport ASTRID_CACHE=/tmp/astrid-cache\n// after: point the materialization target at persistent writable storage\nexport ASTRID_CACHE=$HOME/.cache/astrid","handlingStrategy":"try-catch","validationCode":"use std::path::Path;\n\nfn precheck_materialization(target: &Path) -> Result<(), String> {\n    let parent = target.parent().ok_or(\"target has no parent\")?;\n    std::fs::create_dir_all(parent).map_err(|e| format!(\"parent not creatable: {e}\"))?;\n    let probe = parent.join(\".astrid-write-probe\");\n    std::fs::File::create(&probe)\n        .and_then(|_| std::fs::remove_file(&probe))\n        .map_err(|e| format!(\"cache volume not writable: {e}\"))?;\n    let free = fs4_free_space(parent).unwrap_or(u64::MAX);\n    if free < 64 * 1024 * 1024 {\n        return Err(format!(\"only {free} bytes free on cache volume\"));\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match ensure_published_materialization(&target, &principal, &manifest, &snapshot) {\n    Ok(m) => Ok(m),\n    Err(e) if e.to_string().contains(\"materialize durable capsule package\") => {\n        // full chain is preserved via {error:#}\n        if e.to_string().contains(\"No space left\") {\n            free_cache_space()?; // then retry once\n            ensure_published_materialization(&target, &principal, &manifest, &snapshot)\n        } else if e.to_string().contains(\"corrupt\") || e.to_string().contains(\"checksum\") {\n            Err(e.context(\"stored package appears corrupted; re-publish or re-fetch it\"))\n        } else {\n            Err(e)\n        }\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Monitor free space on the cache volume; materialization fails hard when the disk is full.","Re-publish/re-fetch package snapshots after interrupted uploads; treat checksum failures as corrupt stored data.","Serialize materialization per target (lock) so concurrent runs do not race on the same directory.","Run under a user/sandbox that is allowed to write the cache path; on CI, cache into the workspace, not read-only system paths."],"tags":["filesystem","materialization","disk","package-install"],"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"}