{"record":{"id":"e4e7b18da1e9a01b","repo":"jdx/mise","slug":"remote-cache-blob-pack-blob-count-metadata-mismatc","errorCode":null,"errorMessage":"remote cache blob pack blob count metadata mismatch: expected {}, decoded {}","messagePattern":"remote cache blob pack blob count metadata mismatch: expected (.+?), decoded (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/lib.rs","lineNumber":330,"sourceCode":"            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!(\n                \"remote cache blob pack payload byte metadata mismatch: expected {}, decoded {}\",\n                payload_bytes,\n                decoded.payload_bytes\n            );\n        }\n        Ok(BlobPackResponseStats {\n            blob_count: self.blob_count.unwrap_or(decoded.blob_count),\n            payload_bytes: self.payload_bytes.unwrap_or(decoded.payload_bytes),\n            framed_bytes: self.content_length.unwrap_or(decoded.framed_bytes),","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/crates/mise-cache-core/src/lib.rs#L312-L348","documentation":"Thrown while validating a blob-pack download (crates/mise-cache-core/src/lib.rs:330): the response's blob-count metadata header (BLOB_PACK_BLOBS_HEADER, parsed in from_headers) disagrees with blob_count — the number of blob records actually decoded from the pack stream. The server promised N blobs but the framed body contained a different count.","triggerScenarios":"Calling the blob-pack download path (get_blob_pack -> decode_blob_pack at lib.rs:899) against a server whose blob-count header does not match the records in the body — e.g. the server added/removed a blob after computing the header, or the stream was cut short before the last records arrived (which would also shift framed_bytes).","commonSituations":"Server-side race between pack generation and concurrent blob uploads; a proxy truncating the response body; version skew between client and server pack formats; a custom cache server implementing the pack endpoint incorrectly.","solutions":["Retry the download — transient truncation or a server-side race often resolves itself","Fall back to per-blob downloads by disabling blob packs for this remote, then re-enable to test","Verify the response is not being modified in transit (compression, truncation) by proxies","If you control the server, compute the blob-count header from the exact byte stream serialized, under the same lock as pack generation"],"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(\"blob count metadata mismatch\") => {\n        client.get_blob_pack(&digests, &staging).await // one retry\n            .or_else(|_| fallback_per_blob(&client, &digests))\n    }\n    other => other?,\n}","preventionTips":["Retry once, then fall back to per-blob GETs which are independently digest-verified","If you run the server, generate pack headers and body under the same snapshot/lock","Track per-endpoint mismatch counts to distinguish transient races from systematic bugs"],"tags":["mise","cache","network","integrity","blob-pack","count-mismatch"],"backgroundTag":"response-body-corruption","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","schemaVersion":2},"datasetVersion":"2026-08-23T11:17:13.642Z"}