{"record":{"id":"275e09213452b112","repo":"jdx/mise","slug":"encrypted-tracked-files-require-history-encryptio","errorCode":null,"errorMessage":"encrypted tracked files require [history.encryption].recipients; nothing was committed","messagePattern":"encrypted tracked files require \\[history\\.encryption\\]\\.recipients; nothing was committed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/shadow.rs","lineNumber":375,"sourceCode":"        manifest.recipients.sort();\n        manifest.recipients.dedup();\n        let mut result = self.capture_tracked_files(walk, &manifest.recipients, interactive)?;\n        result.tree = manifest.preserve_other_files(self, &result.tree)?;\n        result.tree = manifest.write(self, &result.tree)?;\n        Ok(result)\n    }\n\n    fn capture_tracked_files(\n        &self,\n        walk: &super::tracked::Walk,\n        recipient_strings: &[String],\n        interactive: bool,\n    ) -> Result<CaptureResult> {\n        if !walk.files.values().any(|(_, policy)| policy.encrypt) {\n            return self.capture(&walk.roots);\n        }\n        if recipient_strings.is_empty() {\n            bail!(\n                \"encrypted tracked files require [history.encryption].recipients; nothing was committed\"\n            );\n        }\n        let mut normalized = recipient_strings.to_vec();\n        normalized.sort();\n        normalized.dedup();\n        let scheme = crate::hash::hash_sha256_to_str(&normalized.join(\"\\n\"));\n        let cache_path = self.dir().parent().unwrap().join(\"index/encryption.json\");\n        let cache_key = encryption_cache_key(self.dir().parent().unwrap())?;\n        let mut cache: BTreeMap<String, EncryptionCacheEntry> = std::fs::read(&cache_path)\n            .ok()\n            .and_then(|bytes| serde_json::from_slice(&bytes).ok())\n            .unwrap_or_default();\n        let mut roots = walk.roots.clone();\n        let mut overlays = vec![];\n        let mut recipients = None;\n        for root in &mut roots {\n            let encrypted: Vec<_> = root","sourceCodeStart":357,"sourceCodeEnd":393,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/shadow.rs#L357-L393","documentation":"capture_tracked_files supports encrypting tracked files, which requires age-style recipient keys from [history.encryption].recipients. If any file's policy requests encryption but no recipients are configured, committing would produce unreadable data, so it bails before committing anything.","triggerScenarios":"Calling capture_tracked on a walk where at least one file has policy.encrypt = true while recipient_strings is empty — i.e. an encrypt rule matched files but [history.encryption].recipients was never set.","commonSituations":"Adding an encryption policy/rule to history config without configuring recipients; recipients key present but empty; config in a scoped file that isn't loaded.","solutions":["Add recipient public keys under [history.encryption].recipients in mise config","Verify the config file containing recipients is actually loaded (correct scope/profile)","If encryption wasn't intended, remove or fix the encrypt policy on the matched files"],"exampleFix":"# before\n[history.encryption]\n# recipients missing\n# after\n[history.encryption]\nrecipients = [\"age1qy...key1\", \"age1abc...key2\"]","handlingStrategy":"validation","validationCode":"let wants_encryption = history.has_encrypted_tracked_files();\nlet recipients = history.encryption_recipients();\nif wants_encryption && recipients.is_empty() {\n    eprintln!(\"set [history.encryption].recipients before committing encrypted files\");\n    return Ok(());\n}","typeGuard":null,"tryCatchPattern":"match history.capture_tracked(recipients, interactive) {\n    Err(e) if e.to_string().contains(\"recipients; nothing was committed\") => {\n        eprintln!(\"configure [history.encryption].recipients, then retry\");\n    }\n    other => other?,\n}","preventionTips":["Configure recipients before enabling any encrypt policy","Keep [history.encryption] in the global config so it is always loaded","Test capture after adding encryption rules to catch missing recipients early"],"tags":["config","encryption","history"],"backgroundTag":"missing-required-config-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"}