jdx/mise · error

encrypted tracked files require…

Error message

encrypted tracked files require [history.encryption].recipients; nothing was committed

What it means

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.

Solutions

  1. Add recipient public keys under [history.encryption].recipients in mise config
  2. Verify the config file containing recipients is actually loaded (correct scope/profile)
  3. If encryption wasn't intended, remove or fix the encrypt policy on the matched files

Example fix

# before
[history.encryption]
# recipients missing
# after
[history.encryption]
recipients = ["age1qy...key1", "age1abc...key2"]
Defensive patterns

Strategy: validation

Validate before calling

let wants_encryption = history.has_encrypted_tracked_files();
let recipients = history.encryption_recipients();
if wants_encryption && recipients.is_empty() {
    eprintln!("set [history.encryption].recipients before committing encrypted files");
    return Ok(());
}

Try / catch

match history.capture_tracked(recipients, interactive) {
    Err(e) if e.to_string().contains("recipients; nothing was committed") => {
        eprintln!("configure [history.encryption].recipients, then retry");
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/275e09213452b112. Report an issue: GitHub.

Appendix: source

Thrown at src/system/history/shadow.rs:375

        manifest.recipients.sort();
        manifest.recipients.dedup();
        let mut result = self.capture_tracked_files(walk, &manifest.recipients, interactive)?;
        result.tree = manifest.preserve_other_files(self, &result.tree)?;
        result.tree = manifest.write(self, &result.tree)?;
        Ok(result)
    }

    fn capture_tracked_files(
        &self,
        walk: &super::tracked::Walk,
        recipient_strings: &[String],
        interactive: bool,
    ) -> Result<CaptureResult> {
        if !walk.files.values().any(|(_, policy)| policy.encrypt) {
            return self.capture(&walk.roots);
        }
        if recipient_strings.is_empty() {
            bail!(
                "encrypted tracked files require [history.encryption].recipients; nothing was committed"
            );
        }
        let mut normalized = recipient_strings.to_vec();
        normalized.sort();
        normalized.dedup();
        let scheme = crate::hash::hash_sha256_to_str(&normalized.join("\n"));
        let cache_path = self.dir().parent().unwrap().join("index/encryption.json");
        let cache_key = encryption_cache_key(self.dir().parent().unwrap())?;
        let mut cache: BTreeMap<String, EncryptionCacheEntry> = std::fs::read(&cache_path)
            .ok()
            .and_then(|bytes| serde_json::from_slice(&bytes).ok())
            .unwrap_or_default();
        let mut roots = walk.roots.clone();
        let mut overlays = vec![];
        let mut recipients = None;
        for root in &mut roots {
            let encrypted: Vec<_> = root

View on GitHub (pinned to 533346cc37)