{"record":{"id":"69c4963860edcb5d","repo":"astrid-runtime/astrid","slug":"distro-lock-capsule-capsule-has-an-invalid-bla","errorCode":null,"errorMessage":"Distro.lock capsule '{capsule}' has an invalid BLAKE3 hash","messagePattern":"Distro\\.lock capsule '(.+?)' has an invalid BLAKE3 hash","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/init_grant.rs","lineNumber":429,"sourceCode":"                \"Distro.lock capsule '{}' content blob is missing or unreadable at {}\",\n                capsule,\n                blob_path.display()\n            )\n        })?\n    };\n    let actual = blake3::hash(&bytes);\n    if actual != locked {\n        bail!(\"Distro.lock capsule '{capsule}' content blob bytes do not match hash {locked_hash}\");\n    }\n    Ok(())\n}\n\nfn parse_locked_blake3(capsule: &CapsuleId, value: &str) -> anyhow::Result<blake3::Hash> {\n    let Some(hex) = value.strip_prefix(\"blake3:\") else {\n        bail!(\"Distro.lock capsule '{capsule}' requires a canonical blake3:<hex> WASM hash\");\n    };\n    let hash = blake3::Hash::from_hex(hex).map_err(|_| {\n        anyhow::anyhow!(\"Distro.lock capsule '{capsule}' has an invalid BLAKE3 hash\")\n    })?;\n    if hex.len() != 64 || hash.to_hex().as_str() != hex {\n        bail!(\"Distro.lock capsule '{capsule}' requires a canonical lowercase BLAKE3 hash\");\n    }\n    Ok(hash)\n}\n\nfn manifest_declares_wasm(manifest: &CapsuleManifest) -> bool {\n    manifest\n        .components\n        .iter()\n        .any(|component| component.path.extension().and_then(|ext| ext.to_str()) == Some(\"wasm\"))\n}\n\n/// Apply capsule-access grants for the installed set (opt-in), or print\n/// the discoverability hint when the flag was omitted.\n///\n/// On the grant path the capsules are already installed and the lock is","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/init_grant.rs#L411-L447","documentation":"The lock's WASM hash string must parse as a BLAKE3 hash after the `blake3:` prefix. `blake3::Hash::from_hex` failed, so the value after the prefix is not valid hexadecimal of the right length. The library refuses to validate the capsule because it cannot even parse the pinned hash, distinguishing this from the separate canonical-form (lowercase, 64 chars) check.","triggerScenarios":"`parse_locked_blake3` receives a value like `blake3:xyz...` where the hex part contains invalid characters or wrong length, making `from_hex` return Err. Any hand-edited or programmatically generated lock with a malformed hash triggers this.","commonSituations":"Hand-editing Distro.lock and mistyping the hash; using an MD5/SHA-256 hex string instead of BLAKE3; truncating the hash when copying; generating the lock with a script that writes a placeholder value.","solutions":["Regenerate Distro.lock so it contains the correct `blake3:<64-hex>` hash from the built WASM","Compute the correct hash with `b3sum <capsule>.wasm` and paste it (keeping the `blake3:` prefix)","Restore the lock from the signed source (`Distro.lock` fetch) instead of editing locally","Ensure any tooling writing the lock emits lowercase 64-character hex"],"exampleFix":"# before\nwasm = \"blake3:abc123\"\n# after\nwasm = \"blake3:2f1e...\"  # full 64-char lowercase hex from b3sum","handlingStrategy":"validation","validationCode":"fn is_valid_blake3_lock(value: &str) -> bool {\n    value.strip_prefix(\"blake3:\")\n        .map(|h| h.len() == 64 && h.bytes().all(|b| b.is_ascii_hexdigit()))\n        .unwrap_or(false)\n}","typeGuard":"fn canonical_blake3(value: &str) -> Option<blake3::Hash> {\n    let hex = value.strip_prefix(\"blake3:\")?;\n    let hash = blake3::Hash::from_hex(hex).ok()?;\n    (hex.len() == 64 && hash.to_hex().as_str() == hex).then_some(hash)\n}","tryCatchPattern":"match res {\n    Err(e) if e.to_string().contains(\"invalid BLAKE3 hash\") => regenerate_lock(),\n    other => other,\n}","preventionTips":["Never hand-edit hash fields in Distro.lock; use b3sum","Always keep the `blake3:` prefix and 64-char lowercase hex","Validate the lock after any scripted generation","Restore locks from the signed source rather than patching"],"tags":["cli","distro-lock","blake3","hash","validation"],"backgroundTag":"invalid-argument-format","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"}