{"record":{"id":"48abebd22c10cf8c","repo":"jdx/mise","slug":"no-age-recipients-to-encrypt-for","errorCode":null,"errorMessage":"no age recipients to encrypt for","messagePattern":"no age recipients to encrypt for","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/agecrypt.rs","lineNumber":154,"sourceCode":"\npub(crate) fn read_bounded(reader: impl Read, limit: u64) -> std::io::Result<Vec<u8>> {\n    let mut bytes = Vec::new();\n    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    }","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/agecrypt.rs#L136-L172","documentation":"encrypt_bytes requires at least one age recipient (public key) to encrypt for. An empty recipients slice would produce ciphertext no one can decrypt, so the function fails fast with this error before doing any work.","triggerScenarios":"Calling encrypt_bytes with recipients == &[] — e.g. no identities/keys were configured, key loading produced zero recipients, or a plugin protocol call passed an empty recipient list.","commonSituations":"Missing or empty MISE_AGE_RECIPIENTS-style config, age public key file empty or not parsed, plugin protocol handshake returned no recovery recipients, variable holding the key never populated.","solutions":["Configure at least one age recipient public key (age1... / ssh-ed25519) before encrypting","Check that the key file or env var feeding recipient loading is non-empty and parsed correctly","In plugin protocol usage, ensure the peer returned its recovery recipients during the handshake","Validate the recipients list length at the call site and surface a clearer message to the user"],"exampleFix":"// before\nlet recipients: Vec<Box<dyn Recipient + Send>> = load_recipients()?; // may be empty\nlet ct = encrypt_bytes(&plaintext, &recipients)?;\n// after\nlet recipients = load_recipients()?;\nanyhow::ensure!(!recipients.is_empty(), \"no age recipients configured\");\nlet ct = encrypt_bytes(&plaintext, &recipients)?;","handlingStrategy":"validation","validationCode":"// Rust (caller-side check)\nanyhow::ensure!(!recipients.is_empty(), \"configure at least one age recipient (MISE_AGE_RECIPIENTS)\");\nlet ct = encrypt_bytes(&plaintext, &recipients)?;","typeGuard":"fn has_recipients(recipients: &[Box<dyn Recipient + Send>]) -> bool {\n    !recipients.is_empty()\n}","tryCatchPattern":"match encrypt_bytes(&plaintext, &recipients) {\n    Err(e) if e.to_string().contains(\"no age recipients\") => {\n        eprintln!(\"set your age public key before encrypting\");\n    }\n    other => other,\n}","preventionTips":["Validate recipient configuration at startup","Fail loudly when key loading yields zero keys instead of passing empty slices","Test the encrypt path in CI with a real test key"],"tags":["age","encryption","config"],"backgroundTag":"empty-required-field","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"}