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

  1. Compute action keys with CacheDigest::blake3(&canonical_json(&action_record)?) — never sha256
  2. If migrating from sha256 keys, recompute digests and re-upload; old server entries simply become cache misses
  3. 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

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


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/4ecf2bea3d92b8cd. Report an issue: GitHub.