jdx/mise · error
local action keys must use blake3
Error message
local action keys must use blake3
What it means
`LocalActionCache::path_for` resolves the storage path for an action digest and requires the digest's algorithm to be exactly `blake3`. Sha-256 digests are valid for CAS blobs, but the action-result index is keyed by blake3 only, so any other algorithm is rejected before filesystem access. Every `find`/`store` call goes through `path_for`, so this guard covers the whole action cache API.
Solutions
- Compute action keys with `CacheDigest::blake3(bytes)` or `CacheDigest::blake3_file(&path)`.
- When a digest arrives from external data, check `digest.algorithm == "blake3"` before using it as an action key.
- Reserve sha-256 digests for blob storage only.
Example fix
// before: sha256 action key - path_for bails
let action = CacheDigest { algorithm: "sha256".into(), hash: sha256_hex, size };
actions.find(&action)?;
// after: action keys are blake3
let action = CacheDigest::blake3(&manifest_bytes);
actions.find(&action)?; Defensive patterns
Strategy: type-guard
Type guard
fn is_action_key(digest: &CacheDigest) -> bool {
digest.algorithm == "blake3" && digest.validate().is_ok()
}
// usage
if is_action_key(&digest) {
let found = actions.find(&digest)?;
} else {
// sha256 digests are blob keys only: store via LocalCas, never LocalActionCache
} Prevention
- Have one constructor for action keys (always CacheDigest::blake3/blake3_file) and use it everywhere.
- Guard deserialized digests with the type guard before touching the action cache.
- Reserve sha256 for CAS blob digests.
When it happens
Trigger: Constructing a `CacheDigest` with `algorithm: "sha256"` (or any non-blake3 value) and passing it to `LocalActionCache::find`/`store`/`path_for`; deserializing an action digest from remote or JSON data that used sha256; reusing blob digests as action keys.
Common situations: Interop code hashing action manifests with sha-256 out of habit; mixing digest constructors between the blob CAS (blake3 or sha256) and the action cache (blake3 only); digests arriving from external systems.
Related errors
- cannot publish an action result with a missing blob
- local action key already has a different result
- local action result is invalid
- unsupported local action result version
- bytes do not match the declared CAS digest
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/79a4b0b3186b3728.
Report an issue: GitHub.
Appendix: source
Thrown at crates/mise-cache-core/src/local.rs:177
fs::set_permissions(path, permissions)?;
Ok(())
}
impl LocalActionCache {
/// Create an action-result index beneath `root`.
pub fn new(root: impl Into<PathBuf>) -> Self {
let root = root.into();
Self {
cas: LocalCas::new(root.clone()),
root,
}
}
/// Resolve the storage path for an action digest.
pub fn path_for(&self, action: &CacheDigest) -> Result<PathBuf> {
action.validate()?;
if action.algorithm != "blake3" {
bail!("local action keys must use blake3");
}
Ok(self
.root
.join("action-results/v1")
.join(&action.algorithm)
.join(&action.hash[..2])
.join(format!("{}-{}.json", action.hash, action.size)))
}
/// Find and strictly validate a canonical action result.
pub fn find(&self, action: &CacheDigest) -> Result<Option<RemoteActionResult>> {
let path = self.path_for(action)?;
if !path.exists() {
return Ok(None);
}
let bytes = fs::read(&path)?;
let result: RemoteActionResult = serde_json::from_slice(&bytes)?;
if result.version != 1 || result.action != *action || canonical_json(&result)? != bytes {View on GitHub (pinned to 6f52dcdf99)