jdx/mise · error
encrypt an external dotfile source instead of configuration
Error message
encrypt an external dotfile source instead of configuration: {path} What it means
Thrown by `encode` when asked to encrypt a file that is itself one of the sync system's control/configuration files (`control_file(path)` is true). The sync configuration must stay plaintext so the tool can read it; encrypting it would make the setup store unreadable. Users should encrypt external dotfiles instead.
Solutions
- Remove the setup configuration file from the encryption list.
- Refine the glob so only external dotfiles match.
- Keep sync configuration in a dedicated directory excluded from encryption.
Example fix
// before encrypt = ["~/.config/*"] // after encrypt = ["~/.config/*", "!~/.config/setup-config.toml"]
Defensive patterns
Strategy: validation
Validate before calling
if (isControlFile(path)) {
throw new Error(`cannot encrypt setup configuration: ${path}`);
}
await sync.encrypt(path, mode, content); Type guard
function isExternalDotfile(path: string): boolean {
return !isControlFile(path);
} Try / catch
try {
await sync.encrypt(path, mode, content);
} catch (e) {
if (/instead of configuration/.test(String(e))) {
log.warn(`excluded control file from encryption: ${path}`);
} else throw e;
} Prevention
- Keep encryption include lists targeted at dotfiles only.
- Review expanded glob matches before committing an encryption config.
- Maintain an explicit deny-list for control files.
When it happens
Trigger: Calling `encode` (via `encrypt`) on a path for which `control_file(path)` returns true — i.e. the setup configuration file itself is listed for encryption.
Common situations: Glob patterns like `~/.config/**` that include the sync config file; explicitly adding the setup store's configuration to the encrypted-files list.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- setup configuration itself cannot be encrypted
- encrypted file does not match its path or mode
- encrypted file exceeds the size limit
- [history.encryption].recipients must not be empty…
- relay log format must be text or jsonl
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/9c645d31e52026cb.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/sync/files.rs:342
.map(|recipient| {
agecrypt::parse_recipient_mode(recipient, interactive)?
.ok_or_else(|| eyre::eyre!("invalid age recipient: {recipient}"))
})
.collect::<Result<Vec<_>>>()?;
encrypt(repo, path, object, &scheme, &recipients)
}
/// Encrypt bytes before they enter Git. Callers may store only the returned
/// envelope, never the input or the decrypted payload in repository objects.
pub(crate) fn encode(
path: &str,
mode: &str,
content: &[u8],
scheme: &str,
recipients: &[Box<dyn age::Recipient + Send>],
) -> Result<Vec<u8>> {
if control_file(path) {
bail!("encrypt an external dotfile source instead of configuration: {path}");
}
if !matches!(mode, "100644" | "100755" | "120000") {
bail!("unsupported encrypted file mode: {path}");
}
let inner = Plaintext {
path: path.into(),
mode: mode.into(),
scheme: scheme.into(),
content: Bytes(content.to_vec()),
};
let bytes = rmp_serde::to_vec_named(&inner)?;
let outer = Envelope {
path: path.into(),
mode: mode.into(),
scheme: scheme.into(),
ciphertext: Bytes(agecrypt::encrypt_bytes(&bytes, recipients)?),
};
let mut encoded = MAGIC.to_vec();View on GitHub (pinned to 533346cc37)