{"record":{"id":"d8650cc4cee01bd5","repo":"jdx/mise","slug":"plaintext-exceeds-the-size-limit","errorCode":null,"errorMessage":"plaintext exceeds the size limit","messagePattern":"plaintext exceeds the size limit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/agecrypt.rs","lineNumber":157,"sourceCode":"    reader.take(limit + 1).read_to_end(&mut bytes)?;\n    if bytes.len() as u64 > limit {\n        return Err(std::io::Error::other(\n            \"encrypted content exceeds the size limit\",\n        ));\n    }\n    Ok(bytes)\n}\n\n/// zstd-compressed, then age-encrypted for `recipients`.\npub(crate) fn encrypt_bytes(\n    plaintext: &[u8],\n    recipients: &[Box<dyn Recipient + Send>],\n) -> Result<Vec<u8>> {\n    if recipients.is_empty() {\n        bail!(\"no age recipients to encrypt for\");\n    }\n    if plaintext.len() as u64 > MAX_PLAINTEXT_BYTES {\n        bail!(\"plaintext exceeds the size limit\");\n    }\n    let compressed = zstd::encode_all(plaintext, ZSTD_COMPRESSION_LEVEL)?;\n    if compressed.len() as u64 > MAX_ENCRYPTED_BYTES {\n        bail!(\"compressed payload exceeds the size limit\");\n    }\n    let encryptor =\n        Encryptor::with_recipients(recipients.iter().map(|r| r.as_ref() as &dyn Recipient))\n            .map_err(|e| eyre!(\"creating the age encryptor: {e}\"))?;\n    let mut out = Vec::new();\n    let mut writer = encryptor.wrap_output(&mut out)?;\n    writer.write_all(&compressed)?;\n    writer.finish()?;\n    if out.len() as u64 > MAX_ENCRYPTED_BYTES {\n        bail!(\"encrypted payload exceeds the size limit\");\n    }\n    Ok(out)\n}\n","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/agecrypt.rs#L139-L175","documentation":"encrypt_bytes enforces MAX_PLAINTEXT_BYTES on the input before compressing. Plaintext larger than this limit is refused because the encrypted output (and any protocol framing) is designed around bounded payload sizes.","triggerScenarios":"Calling encrypt_bytes with plaintext.len() > MAX_PLAINTEXT_BYTES — e.g. encrypting a huge file, a large environment snapshot, or unbounded accumulated secrets buffers.","commonSituations":"Trying to encrypt a multi-gigabyte artifact, plugin protocol payloads that grew due to a bug, accidentally passing an entire directory archive instead of the intended small secret blob.","solutions":["Split the data into chunks below MAX_PLAINTEXT_BYTES and encrypt each chunk","Compress or trim the payload before encryption (large env dumps often contain redundant data)","Store large data out-of-band and encrypt only a key/reference to it","Check the caller for a bug that is accumulating plaintext without bound"],"exampleFix":"// before\nlet ct = encrypt_bytes(&entire_archive, &recipients)?; // too large\n// after\nfor chunk in split_chunks(&entire_archive, MAX_PLAINTEXT_BYTES) {\n    let ct = encrypt_bytes(chunk, &recipients)?;\n    write_chunk(ct);\n}","handlingStrategy":"validation","validationCode":"// Rust (caller-side check)\nconst MAX_PLAINTEXT_BYTES: u64 = /* crate limit */;\nanyhow::ensure!(plaintext.len() as u64 <= MAX_PLAINTEXT_BYTES, \"payload too large to encrypt\");","typeGuard":"fn within_plaintext_limit(plaintext: &[u8], max: u64) -> bool {\n    (plaintext.len() as u64) <= max\n}","tryCatchPattern":"match encrypt_bytes(&plaintext, &recipients) {\n    Err(e) if e.to_string().contains(\"plaintext exceeds\") => {\n        eprintln!(\"split the payload or store it out-of-band\");\n    }\n    other => other,\n}","preventionTips":["Check payload size before encrypting, not after failure","Design data formats to keep encrypted payloads small","Watch for unbounded accumulation in env/snapshot buffers"],"tags":["age","encryption","size-limit"],"backgroundTag":"payload-too-large","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}