jdx/mise · error · eyre::Report

remote cache blob failed digest verification

Error message

remote cache blob failed digest verification

What it means

get_blob downloads a blob into memory and verifies both the byte length and the hash against the requested digest via matches_bytes. A mismatch means the server returned different bytes than the content-addressed key promised — corruption, truncation, or a misbehaving server. The bail! is not classified as transient by retry_async (only reqwest-level failures are), so it is not automatically retried.

Source

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

    }

    pub async fn get_blob(
        &self,
        digest: &CacheDigest,
        media_type: &'static str,
    ) -> Result<Vec<u8>> {
        digest.validate()?;
        let url = self.blob_endpoint(digest)?;
        retry_async("GET", &url, self.retries, || async {
            let response = self
                .request(reqwest::Method::GET, url.clone(), media_type)
                .await?
                .send()
                .await?
                .error_for_status()?;
            let bytes = response.bytes().await?.to_vec();
            if !digest.matches_bytes(&bytes)? {
                bail!("remote cache blob failed digest verification");
            }
            Ok(bytes)
        })
        .await
    }

    pub async fn get_blob_file(
        &self,
        digest: &CacheDigest,
        staging_dir: &Path,
    ) -> Result<tempfile::NamedTempFile> {
        let url = self.blob_endpoint(digest)?;
        let download = retry_async("GET", &url, self.retries, || async {
            let mut response = self
                .request(reqwest::Method::GET, url.clone(), BLOB_MEDIA_TYPE)
                .await?
                .send()
                .await?;

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Treat the error as a cache miss and rebuild the content locally instead of retrying the same digest
  2. Once correct bytes are confirmed locally, re-upload via put_blob (If-None-Match: *); a wrongly-stored existing entry may additionally need server-side deletion
  3. Check intermediaries that rewrite bodies for the blob media type (application/octet-stream)
  4. If only one hash consistently fails while others work, delete that object server-side and re-upload

Example fix

// before
let bytes = client.get_blob(&digest, media).await?;

// after: fall back to rebuilding on digest mismatch
let bytes = match client.get_blob(&digest, media).await {
    Ok(bytes) => bytes,
    Err(report) if report.to_string().contains("failed digest verification") => {
        rebuild_locally(&digest)?
    }
    Err(report) => return Err(report),
};
Defensive patterns

Strategy: fallback

Try / catch

let bytes = match client.get_blob(&digest, media).await {
    Ok(bytes) => bytes,
    Err(report) if report.to_string().contains("failed digest verification") => {
        rebuild_locally(&digest)? // miss, not a retryable network error
    }
    Err(report) => return Err(report),
};

Prevention

When it happens

Trigger: Calling get_blob for a digest the server stored incorrectly; a proxy truncating or modifying the body; a server that resolves the wrong object for the algorithm/hash/size path; an upload that was recorded as complete before the body finished.

Common situations: Bit corruption or partial writes on the cache server; gateways that rewrite bodies (compression, AV scanning); hostile interception on an unauthenticated plain-HTTP link; a server bug after a version upgrade.

Related errors


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