jdx/mise · error · eyre::Report

remote action manifest keys must use blake3

Error message

remote action manifest keys must use blake3

What it means

Action-manifest keys are scoped like action-result keys: blake3 only. action_manifest_endpoint() validates the digest and then rejects any algorithm other than "blake3" before constructing the URL for get_action_manifest/put_action_manifest. This keeps manifest keys consistent with the blake3 ETag contract used for manifest bodies.

Source

Thrown at crates/mise-cache-core/src/lib.rs:326

        }
        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" {
            bail!("remote action manifest keys must use blake3");
        }
        Ok(self.base_url.join(&format!(
            "v{PROTOCOL_VERSION}/action-manifests/{}/{}/{}",
            key.algorithm, key.hash, key.size
        ))?)
    }

    async fn request(
        &self,
        method: reqwest::Method,
        url: Url,
        media_type: &'static str,
    ) -> Result<reqwest::RequestBuilder> {
        let request = self
            .client
            .request(method, url)
            .header(PROTOCOL_HEADER, u16::from(PROTOCOL_VERSION))
            .header(NAMESPACE_HEADER, &self.namespace)

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Derive manifest keys with CacheDigest::blake3 over the exact manifest bytes
  2. Keep one code path for key digests (blake3) and a separate one for blob digests if you need sha256 blobs
  3. Add a debug assert or pre-check that key.algorithm == "blake3" before calling the manifest endpoints

Example fix

// before
let key = CacheDigest { algorithm: "sha256".into(), hash, size };
client.get_action_manifest(&key).await?;

// after
let key = CacheDigest::blake3(&manifest_bytes);
client.get_action_manifest(&key).await?;
Defensive patterns

Strategy: validation

Validate before calling

fn manifest_key(bytes: &[u8]) -> CacheDigest {
    CacheDigest::blake3(bytes) // manifest keys are always blake3
}

fn ensure_manifest_key(key: &CacheDigest) -> eyre::Result<()> {
    key.validate()?;
    if key.algorithm != "blake3" {
        eyre::bail!("manifest key must use blake3, got {}", key.algorithm);
    }
    Ok(())
}

Type guard

fn is_blake3_manifest_key(key: &CacheDigest) -> bool {
    key.algorithm == "blake3" && key.validate().is_ok()
}

Prevention

When it happens

Trigger: Passing a sha256 CacheDigest as the key to RemoteCacheClient::get_action_manifest or put_action_manifest; deriving the manifest key from a sha256 blob digest; shared helper code that hashes keys with a configurable algorithm defaulting to sha256.

Common situations: Code paths that compute blob digests (any algorithm) and manifest keys (blake3 only) with the same function; integrations upgraded from an earlier prototype that used sha256 manifest keys.

Related errors


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