jdx/mise · error · eyre::Report
remote cache action keys must use blake3
Error message
remote cache action keys must use blake3
What it means
Although blob digests may use either blake3 or sha256, action-result keys must use blake3 because the action digest is defined as blake3 over the canonical JSON of the action record. action_result_endpoint() rejects any action CacheDigest whose algorithm is not "blake3" before building the request URL. The rule applies to both get_action_result and put_action_result.
Source
Thrown at crates/mise-cache-core/src/lib.rs:307
.connect_timeout(config.connect_timeout)
.read_timeout(config.read_timeout)
.redirect(reqwest::redirect::Policy::none())
.build()?;
let credential = remote_credential(&config, client.clone())?;
Ok(Self {
base_url: normalized_base_url(config.base_url),
namespace: config.namespace,
client,
credential,
download_timeout: config.download_timeout,
retries: config.retries,
})
}
fn action_result_endpoint(&self, action: &CacheDigest) -> Result<Url> {
action.validate()?;
if action.algorithm != "blake3" {
bail!("remote cache action keys must use blake3");
}
Ok(self.base_url.join(&format!(
"v{PROTOCOL_VERSION}/action-results/{}/{}/{}",
action.algorithm, action.hash, action.size
))?)
}
fn blob_endpoint(&self, digest: &CacheDigest) -> Result<Url> {
digest.validate()?;
Ok(self.base_url.join(&format!(
"v{PROTOCOL_VERSION}/blobs/{}/{}/{}",
digest.algorithm, digest.hash, digest.size
))?)
}
fn action_manifest_endpoint(&self, key: &CacheDigest) -> Result<Url> {
key.validate()?;
if key.algorithm != "blake3" {View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Compute action keys with CacheDigest::blake3(&canonical_json(&action_record)?) — never sha256
- If migrating from sha256 keys, recompute digests and re-upload; old server entries simply become cache misses
- Assert action.algorithm == "blake3" in your code before calling get/put_action_result so the failure is localized
Example fix
// before
let action = CacheDigest { algorithm: "sha256".into(), hash: sha256_of_record, size };
client.get_action_result(&action).await?;
// after
use mise_cache_core::{canonical_json, CacheDigest};
let action = CacheDigest::blake3(&canonical_json(&record)?);
client.get_action_result(&action).await?; Defensive patterns
Strategy: validation
Validate before calling
fn action_key(record: &impl serde::Serialize) -> eyre::Result<CacheDigest> {
let bytes = mise_cache_core::canonical_json(record)?;
Ok(CacheDigest::blake3(&bytes)) // action keys are always blake3
}
fn ensure_action_key(action: &CacheDigest) -> eyre::Result<()> {
action.validate()?;
if action.algorithm != "blake3" {
eyre::bail!("action key must use blake3, got {}", action.algorithm);
}
Ok(())
} Type guard
fn is_blake3_action_key(digest: &CacheDigest) -> bool {
digest.algorithm == "blake3" && digest.validate().is_ok()
} Prevention
- Centralize action-digest computation in one helper that always uses blake3 over canonical_json
- Reserve sha256 for blob digests only
- Add debug_assert!(action.algorithm == "blake3") around get/put_action_result call sites
When it happens
Trigger: Passing a sha256 CacheDigest as the action key to RemoteCacheClient::get_action_result/put_action_result; reusing a blob digest (which may legitimately be sha256) as an action key; building a RemoteActionResult whose action field was hashed with sha256.
Common situations: Porting code that hashed everything with sha256 before blake3 became the key algorithm; mixing blob digests and action digests in the same struct or map; test fixtures written with sha256 action keys (the unit test action_result_keys_require_blake3 pins this behavior).
Related errors
- remote action manifest keys must use blake3
- local action keys must use blake3
- unsupported remote cache digest algorithm
- invalid remote cache digest
- remote action result does not match requested action
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/4ecf2bea3d92b8cd.
Report an issue: GitHub.