{"record":{"id":"f2c800eed817f720","repo":"jdx/mise","slug":"experimental-no-age-recipients-provided-use-a","errorCode":null,"errorMessage":"[experimental] No age recipients provided. Use --age-recipient, --age-ssh-recipient, or --age-key-file","messagePattern":"\\[experimental\\] No age recipients provided\\. Use --age-recipient, --age-ssh-recipient, or --age-key-file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cli/set.rs","lineNumber":444,"sourceCode":"        }\n\n        // If no recipients were provided, use defaults\n        if recipients.is_empty()\n            && (self.age_recipient.is_empty()\n                && self.age_ssh_recipient.is_empty()\n                && self.age_key_file.is_none())\n        {\n            recipients = agecrypt::load_recipients_from_defaults().await?;\n        }\n\n        // Load recipients from key file if specified\n        if let Some(key_file) = &self.age_key_file {\n            let key_file_recipients = agecrypt::load_recipients_from_key_file(key_file).await?;\n            recipients.extend(key_file_recipients);\n        }\n\n        if recipients.is_empty() {\n            bail!(\n                \"[experimental] No age recipients provided. Use --age-recipient, --age-ssh-recipient, or --age-key-file\"\n            );\n        }\n\n        Ok(recipients)\n    }\n}\n\nasync fn get_mise_toml(filename: &Path) -> Result<MiseToml> {\n    let path = env::current_dir()?.join(filename);\n    // Before the exists/does-not-exist split, so a `.tool-versions` says why it is refused instead\n    // of failing later as invalid TOML, and so a name mise cannot read back is never created.\n    crate::config::config_file::ensure_writable_as_toml(&path).await?;\n    let mise_toml = if path.exists() {\n        MiseToml::from_file(&path)?\n    } else {\n        MiseToml::init(&path)\n    };","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/cli/set.rs#L426-L462","documentation":"age encryption in `mise set` needs at least one recipient to encrypt to. collect_age_recipients() gathers recipients from --age-recipient, --age-ssh-recipient, --age-key-file, and defaults loaded from config (load_recipients_from_defaults); if the combined list is empty it bails with the flag names. The whole feature is experimental and the caller first gates it with ensure_experimental(\"age encryption\").","triggerScenarios":"Running `mise set --age-encrypt FOO=bar` with none of --age-recipient/--age-ssh-recipient/--age-key-file provided and no recipients configured in config defaults.","commonSituations":"First use of the experimental age feature without reading its setup; expecting config-file defaults to exist when they were never added; enabling --age-encrypt in shared scripts where the operator forgot to pass a key.","solutions":["Pass a recipient explicitly: `mise set --age-encrypt --age-recipient age1xxxxxxxx FOO=bar`","Or use an SSH public key as recipient: `mise set --age-encrypt --age-ssh-recipient ssh-ed25519 AAAA... FOO=bar`","Or point at a recipients file: `mise set --age-encrypt --age-key-file ~/age-recipients.txt FOO=bar`","Configure recipient defaults in your config so flagless `--age-encrypt` works","Make sure the experimental gate is on: `mise settings set experimental true`"],"exampleFix":"# before\nmise set --age-encrypt API_TOKEN=xxx   # [experimental] No age recipients provided.\n\n# after\nmise settings set experimental true\nmise set --age-encrypt --age-recipient age1qy... API_TOKEN=xxx","handlingStrategy":"validation","validationCode":"# fail fast with a clear message instead of letting mise bail\nrecs=()\n[ -n \"${AGE_RECIPIENT:-}\" ] && recs+=(--age-recipient \"$AGE_RECIPIENT\")\n[ -n \"${AGE_SSH_RECIPIENT:-}\" ] && recs+=(--age-ssh-recipient \"$AGE_SSH_RECIPIENT\")\n[ ${#recs[@]} -gt 0 ] || { echo 'no age recipient configured (set AGE_RECIPIENT or pass --age-recipient)' >&2; exit 2; }\nmise set --age-encrypt \"${recs[@]}\" API_TOKEN=\"$token\"","typeGuard":"has_recipient() { [ -n \"${AGE_RECIPIENT:-}\" ] || [ -n \"${AGE_SSH_RECIPIENT:-}\" ] || [ -f \"${AGE_KEY_FILE:-/nonexistent}\" ]; }","tryCatchPattern":"Catch the recipients bail as a configuration error: print setup instructions (generate an age key via `age-keygen`, or reuse an SSH public key) and abort — retrying without adding a recipient always fails.","preventionTips":["Store the recipient in a stable env var or config default so scripts never run recipient-less","Keep the private key available where decryption is needed ( mise set reads decrypt via config defaults)","Remember the feature is experimental: gate it behind `mise settings set experimental true` in setup scripts"],"tags":["age","encryption","env","experimental","missing-key","mise"],"backgroundTag":"missing-encryption-key","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}