{"record":{"id":"6911d56dd93b4f93","repo":"jdx/mise","slug":"object-exceeds-the-encrypted-content-size-limit","errorCode":null,"errorMessage":"object exceeds the encrypted content size limit","messagePattern":"object exceeds the encrypted content size limit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/shadow.rs","lineNumber":795,"sourceCode":"        if let Some(bytes) = self.transient_blob(oid) {\n            return Ok(bytes);\n        }\n        self.git\n            .output(PlumbingCall::new([\"cat-file\", \"blob\", oid]))\n            .wrap_err_with(|| format!(\"reading {oid}\"))\n    }\n\n    pub(crate) fn blob_starts_with(&self, oid: &str, prefix: &[u8]) -> Result<bool> {\n        if let Some(bytes) = self.transient_blob(oid) {\n            return Ok(bytes.starts_with(prefix));\n        }\n        self.git.blob_starts_with(oid, prefix)\n    }\n\n    pub(crate) fn cat_object_bounded(&self, oid: &str, limit: u64) -> Result<Vec<u8>> {\n        if let Some(bytes) = self.transient_blob(oid) {\n            if bytes.len() as u64 > limit {\n                bail!(\"object exceeds the encrypted content size limit\");\n            }\n            return Ok(bytes);\n        }\n        let size: u64 = self\n            .output_str(PlumbingCall::new([\"cat-file\", \"-s\", oid]))?\n            .trim()\n            .parse()?;\n        if size > limit {\n            eyre::bail!(\"object exceeds the encrypted content size limit\");\n        }\n        self.cat_object(oid)\n    }\n\n    pub(crate) fn hash_blob(&self, bytes: &[u8]) -> Result<String> {\n        self.output_str(PlumbingCall::new([\"hash-object\", \"-w\", \"--stdin\"]).stdin(bytes))\n    }\n\n    /// Compute the normal Git identity without writing an object. Read APIs","sourceCodeStart":777,"sourceCodeEnd":813,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/shadow.rs#L777-L813","documentation":"cat_object_bounded enforces a maximum plaintext size for objects read from history. For transient (in-memory) blobs it checks the byte length before returning; exceeding the caller's limit bails rather than loading an oversized object into memory.","triggerScenarios":"read/envelope/encrypt/detect calls cat_object_bounded with a limit, and the requested oid resolves to a transient blob whose byte length exceeds that limit.","commonSituations":"Trying to display, decrypt, or detect format of a history object (e.g. a very large captured file or envelope) that was stored before limits were tightened or that bypassed the capture-time size check.","solutions":["Exclude or prune the oversized object from the history tree","Reduce the source file size or re-capture with the large file untracked","If a legitimate larger object is needed, use a non-bounded read path that streams instead of buffering"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Rust: check transient blob size before the bounded read\nif let Some(bytes) = transient_blob(oid) {\n    anyhow::ensure!(bytes.len() as u64 <= crate::agecrypt::MAX_PLAINTEXT_BYTES,\n        \"object {oid} exceeds MAX_PLAINTEXT_BYTES\");\n}","typeGuard":"fn within_limit(bytes: &[u8], limit: u64) -> bool {\n    (bytes.len() as u64) <= limit\n}","tryCatchPattern":"match repo.cat_object_bounded(oid, LIMIT) {\n    Err(e) if e.to_string().contains(\"size limit\") => {\n        eprintln!(\"object {oid} too large; stream it with an unbounded reader instead\");\n    }\n    other => other?,\n}","preventionTips":["Keep captured files under MAX_PLAINTEXT_BYTES","Exclude large logs/datasets from tracked paths","Check object sizes before attempting bounded reads"],"tags":["size-limit","history","encryption"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}