{"record":{"id":"80a47b48f1b97c34","repo":"jdx/mise","slug":"remote-cache-blob-pack-content-length-metadata-mis","errorCode":null,"errorMessage":"remote cache blob pack content length metadata mismatch: expected {}, decoded {}","messagePattern":"remote cache blob pack content length metadata mismatch: expected (.+?), decoded (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/lib.rs","lineNumber":321,"sourceCode":"    blob_count: u64,\n    payload_bytes: u64,\n    framed_bytes: u64,\n}\n\nimpl BlobPackResponseMetadata {\n    fn from_headers(headers: &HeaderMap) -> Result<Self> {\n        Ok(Self {\n            content_length: optional_u64_header(headers, CONTENT_LENGTH.as_str())?,\n            blob_count: optional_u64_header(headers, BLOB_PACK_BLOBS_HEADER)?,\n            payload_bytes: optional_u64_header(headers, BLOB_PACK_BYTES_HEADER)?,\n        })\n    }\n\n    fn validate(self, decoded: BlobPackResponseStats) -> Result<BlobPackResponseStats> {\n        if let Some(content_length) = self.content_length\n            && content_length != decoded.framed_bytes\n        {\n            bail!(\n                \"remote cache blob pack content length metadata mismatch: expected {}, decoded {}\",\n                content_length,\n                decoded.framed_bytes\n            );\n        }\n        if let Some(blob_count) = self.blob_count\n            && blob_count != decoded.blob_count\n        {\n            bail!(\n                \"remote cache blob pack blob count metadata mismatch: expected {}, decoded {}\",\n                blob_count,\n                decoded.blob_count\n            );\n        }\n        if let Some(payload_bytes) = self.payload_bytes\n            && payload_bytes != decoded.payload_bytes\n        {\n            bail!(","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/crates/mise-cache-core/src/lib.rs#L303-L339","documentation":"Thrown while validating a blob-pack download (crates/mise-cache-core/src/lib.rs:321): the response carried an X-style blob-pack metadata header-derived content_length (from the Content-Length-style optional header parsed in from_headers), and it does not equal decoded.framed_bytes — the number of bytes actually decoded from the framed pack stream (magic + per-blob records). This is an integrity check that the server's declared size matches the body it sent.","triggerScenarios":"Calling the blob-pack download path (decode_blob_pack at lib.rs:899, fed by get_blob_pack) where the server advertises a content length in its headers that differs from the actual framed stream size — e.g. a proxy rewrote/truncated the body, the server has a bug computing the header, or a chunked/encoded response made the header stale.","commonSituations":"A corporate proxy or CDN re-encoding responses (gzip stripped or applied) so Content-Length no longer matches the decoded bytes; a misbehaving or incompatible remote cache server version; a race where the pack was regenerated server-side between header emission and body streaming.","solutions":["Retry the download once — a transient truncation (dropped connection mid-body) can produce this","Disable blob packs for this remote (the client tracks blob_packs_disabled; falling back to per-blob GETs sidesteps pack metadata entirely) and verify blobs download individually","Check any proxy/CDN between client and cache for body-rewriting (compression, chunked re-framing); bypass it or exclude the pack media type application/vnd.mise.cache-blob-pack.v1","If you operate the server, ensure the metadata headers describe the exact framed payload emitted"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match client.get_blob_pack(&digests, &staging).await {\n    Err(e) if e.to_string().contains(\"content length metadata mismatch\") => {\n        client.disable_blob_packs();\n        for d in &digests { let _ = client.get_blob(d, media_type).await?; } // per-blob fallback\n    }\n    other => other?,\n}","preventionTips":["Exclude application/vnd.mise.cache-blob-pack.v1 responses from proxy compression/re-framing","Retry pack downloads once before falling back — truncation is often transient","Monitor mismatch rate per server; a persistent offender is a server bug, not a client problem"],"tags":["mise","cache","network","integrity","blob-pack","metadata-mismatch"],"backgroundTag":"content-length-mismatch","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","schemaVersion":2},"datasetVersion":"2026-08-23T11:17:13.642Z"}