{"record":{"id":"ec031bb3610a9234","repo":"BoundaryML/baml","slug":"blob-size-mismatch-for-expected-bytes-got-bytes","errorCode":null,"errorMessage":"blob size mismatch for {}; expected {} bytes, got {} bytes","messagePattern":"blob size mismatch for (.+?); expected (.+?) bytes, got (.+?) bytes","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"baml_language/crates/bex_events/src/value/artifact.rs","lineNumber":70,"sourceCode":"            ));\n        }\n        if !self.digest.bytes().all(|byte| byte.is_ascii_hexdigit()) {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid sha256 blob digest; expected only hex characters\",\n            ));\n        }\n        Ok(())\n    }\n\n    fn normalized_digest(&self) -> io::Result<String> {\n        self.validate()?;\n        Ok(self.digest.to_ascii_lowercase())\n    }\n\n    fn verify_bytes(&self, bytes: &[u8]) -> io::Result<()> {\n        if bytes.len() != self.size_bytes {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"blob size mismatch for {}; expected {} bytes, got {} bytes\",\n                    self.digest,\n                    self.size_bytes,\n                    bytes.len()\n                ),\n            ));\n        }\n        let actual = Self::sha256(bytes);\n        if actual.digest != self.digest.to_ascii_lowercase() {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"blob digest mismatch for {}; computed {}\",\n                    self.digest, actual.digest\n                ),\n            ));","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/bex_events/src/value/artifact.rs#L52-L88","documentation":"BlobStore::verify_bytes compares the length of the bytes read from disk against the size_bytes recorded in the BlobRef and fails when they differ. This guarantees content-addressed blobs are read back at exactly their recorded size before the digest check runs. It surfaces to callers as an io::Error with InvalidData kind from read_blob.","triggerScenarios":"read_blob() on a blob file that was truncated, partially written, appended to, or whose BlobRef metadata (size_bytes) points at a different blob version.","commonSituations":"Disk-full or crash during a previous write, manual tampering or editing of files under the blob store root, copying blob files between stores with stale BlobRef metadata, or a run interrupted mid-write leaving a partial .tmp that was promoted incorrectly.","solutions":["Delete the corrupt blob file and re-write it from the original bytes with write_blob(), which recomputes size and digest.","Recompute the source content's SHA-256 and fix the BlobRef's size_bytes/digest if the reference itself is stale.","Restore the blob store from backup or re-run the pipeline that produced the artifact."],"exampleFix":"// before\nlet data = fs::read(&path)?; // truncated file, stale BlobRef\nlet blob = store.read_blob(&blob_ref)?;\n// after\nif !path.exists() || fs::metadata(&path)?.len() != blob_ref.size_bytes {\n    store.write_blob(&blob_ref_from_bytes(original_bytes))?; // re-ingest\n}\nlet blob = store.read_blob(&blob_ref)?;","handlingStrategy":"try-catch","validationCode":"let meta = fs::metadata(&path)?;\nif meta.len() != blob_ref.size_bytes {\n    // size already mismatched; re-ingest blob before calling read_blob\n}","typeGuard":null,"tryCatchPattern":"match store.read_blob(&blob_ref) {\n    Ok(bytes) => bytes,\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => {\n        // corrupt/truncated blob: delete and rewrite from source\n        let _ = fs::remove_file(store.path_for(&blob_ref)?);\n        store.write_blob(&BlobRef::sha256(&original_bytes))?;\n        store.read_blob(&BlobRef::sha256(&original_bytes))?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Write blobs via write_blob() only; it uses temp files and validates size/digest.","Never manually edit, truncate, or copy files inside the blob store directory.","Monitor disk space to avoid partial writes."],"tags":["rust","blob-storage","integrity","checksum"],"backgroundTag":"checksum-mismatch","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}