{"record":{"id":"928926baaa200370","repo":"jdx/mise","slug":"bytes-do-not-match-the-declared-cas-digest","errorCode":null,"errorMessage":"bytes do not match the declared CAS digest","messagePattern":"bytes do not match the declared CAS digest","errorType":"exception","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"crates/mise-cache-core/src/local.rs","lineNumber":60,"sourceCode":"    /// Find and verify a stored object.\n    pub fn find(&self, digest: &CacheDigest) -> Result<Option<PathBuf>> {\n        let path = self.path_for(digest)?;\n        if !path.exists() {\n            return Ok(None);\n        }\n        if !digest.matches_file(&path)? {\n            bail!(\n                \"local CAS blob failed digest verification: {}\",\n                path.display()\n            );\n        }\n        Ok(Some(path))\n    }\n\n    /// Atomically store bytes after verifying their declared digest.\n    pub fn store_bytes(&self, digest: &CacheDigest, bytes: &[u8]) -> Result<PathBuf> {\n        if !digest.matches_bytes(bytes)? {\n            bail!(\"bytes do not match the declared CAS digest\");\n        }\n        self.store_with(digest, |temporary| {\n            temporary.write_all(bytes)?;\n            Ok(())\n        })\n    }\n\n    /// Atomically store a file after verifying its declared digest.\n    pub fn store_file(&self, digest: &CacheDigest, source: &Path) -> Result<PathBuf> {\n        self.store_file_inner(digest, source, true)\n    }\n\n    /// Store a file whose digest was already verified by this crate.\n    pub(crate) fn store_verified_file(\n        &self,\n        digest: &CacheDigest,\n        source: &Path,\n    ) -> Result<PathBuf> {","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/crates/mise-cache-core/src/local.rs#L42-L78","documentation":"LocalCas::store_bytes verifies the supplied bytes against the declared digest (hash and length) before writing anything, so the CAS never publishes content under a key it does not match. This error means the digest was computed from different bytes than the ones passed to the store.","triggerScenarios":"Computing the digest from one buffer and passing different bytes to store_bytes — e.g. re-serializing JSON between hashing and storing; setting the size field independently of the data; hashing compressed data but storing the uncompressed form.","commonSituations":"Pipelines that regenerate content non-deterministically (map ordering, float formatting) between digest computation and storage; serializing with serde_json::to_vec for the digest but canonical_json for storage; unit tests with mismatched fixtures.","solutions":["Compute the digest immediately before storing, from the exact same slice: CacheDigest::blake3(bytes) then cas.store_bytes(&digest, bytes)","Hash the same serialization you store — use canonical_json consistently for protocol objects","If content may change concurrently, snapshot it into a Vec first and hash/store the snapshot"],"exampleFix":"// before: digest and stored bytes diverge\nlet digest = CacheDigest::blake3(&record_bytes);\nlet serialized = serde_json::to_vec(&record)?; // different bytes\ncas.store_bytes(&digest, &serialized)?;\n\n// after: digest and store the exact same buffer\nlet bytes = canonical_json(&record)?;\nlet digest = CacheDigest::blake3(&bytes);\ncas.store_bytes(&digest, &bytes)?;","handlingStrategy":"validation","validationCode":"fn store_invariant(cas: &LocalCas, bytes: &[u8]) -> eyre::Result<PathBuf> {\n    let digest = CacheDigest::blake3(bytes); // digest from the exact bytes being stored\n    cas.store_bytes(&digest, bytes)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Compute the digest from the same buffer in the same expression as the store","Use canonical_json consistently for protocol objects — never mix serde_json::to_vec and canonical_json","Snapshot concurrent content into a Vec before hashing and storing"],"tags":["cas","digest-verification","local-cache"],"backgroundTag":"checksum-verification-failed","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}