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
- Treat the error as a cache miss and rebuild the content locally instead of retrying the same digest
- 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
- Check intermediaries that rewrite bodies for the blob media type (application/octet-stream)
- 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
- Always upload via put_blob from verified local bytes so stored entries match their keys
- Keep transforming proxies off application/octet-stream traffic
- Delete and re-upload a server object that fails verification for the same digest twice
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
- remote action result does not match requested action
- remote action manifest ETag does not match its body
- cached rustc output failed digest verification: {}
- remote action result is missing its output root
- remote cache directory graph contains a cycle
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/429ffb4bb406a3b6.
Report an issue: GitHub.