{"record":{"id":"a73290abfac6b65a","repo":"jdx/mise","slug":"history-encryption-recipients-must-not-be-empty","errorCode":null,"errorMessage":"[history.encryption].recipients must not be empty; configure recipients before capturing encrypted files","messagePattern":"\\[history\\.encryption\\]\\.recipients must not be empty; configure recipients before capturing encrypted files","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/config.rs","lineNumber":51,"sourceCode":"#[serde(deny_unknown_fields)]\npub(crate) struct FileEncryptionConfig {\n    #[serde(default)]\n    pub recipients: Vec<String>,\n}\n\npub(crate) fn file_recipients() -> Result<Vec<String>> {\n    let mut recipients = Vec::new();\n    for (path, layer) in layers()? {\n        if let Some(encryption) = layer.encryption {\n            if !crate::config::config_file::is_trusted(&path) {\n                eyre::bail!(\n                    \"trust the configuration before using its encryption recipients: {}\",\n                    display_path(&path)\n                );\n            }\n            recipients = encryption.recipients;\n            if recipients.is_empty() {\n                eyre::bail!(\n                    \"[history.encryption].recipients must not be empty; configure recipients before capturing encrypted files\"\n                );\n            }\n        }\n    }\n    Ok(recipients)\n}\n\n/// `[history.origin]`.\n#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]\n#[serde(deny_unknown_fields)]\npub(crate) struct OriginTomlConfig {\n    pub url: String,\n    #[serde(default = \"default_branch\")]\n    pub branch: String,\n}\n\nimpl OriginTomlConfig {","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/config.rs#L33-L69","documentation":"`file_recipients()` validates that any config layer declaring `[history.encryption]` actually lists at least one recipient. An empty `recipients` array is rejected because encrypted files captured without recipients could never be decrypted by anyone.","triggerScenarios":"A config file contains `[history.encryption]` with `recipients = []` (or the key present but empty), and any history operation that captures encrypted files calls `file_recipients()`.","commonSituations":"User added the `[history.encryption]` table as a placeholder but hadn't pasted their age/GPG recipient yet; a template scaffolded the section with an empty list.","solutions":["Add at least one recipient under `[history.encryption].recipients` in your config.","Remove the `[history.encryption]` section entirely if encryption isn't intended.","Generate a key first (e.g. `age-keygen`) so you have a recipient string to add."],"exampleFix":"# before\n[history.encryption]\nrecipients = []\n# after\n[history.encryption]\nrecipients = [\"age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p\"]","handlingStrategy":"validation","validationCode":"[ -n \"$recipients\" ] || { echo '[history.encryption].recipients must not be empty'; exit 1; }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never commit a [history.encryption] section with an empty recipients list","Generate keys (e.g. age-keygen) before enabling encryption config","Validate config after scaffolding templates that include encryption blocks"],"tags":["config","encryption","validation"],"backgroundTag":"empty-required-field","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}