jdx/mise · error
encrypted file does not match its path or mode: {path}
Error message
encrypted file does not match its path or mode: {path} What it means
This error comes from the integrity validation of an encrypted-file envelope in mise's history sync. The decrypted inner plaintext must exactly match the outer envelope's path, mode, and scheme, use a safe branch path, and use a supported git mode; any mismatch means the envelope was tampered with, corrupted, or crafted inconsistently. It is thrown by validate() before decrypt() will produce file contents.
Source
Thrown at src/system/history/sync/files.rs:241
// Only encrypted envelopes have this limit; do not change plaintext sync.
let bytes = repo.cat_object_bounded(&object.1, limit)?;
let Some(body) = bytes.strip_prefix(MAGIC) else {
return Ok(None);
};
Ok(Some(
rmp_serde::from_slice(body).wrap_err("invalid encrypted file envelope")?,
))
}
fn validate(path: &str, outer: &Envelope, inner: &Plaintext) -> Result<()> {
if outer.path != path
|| inner.path != path
|| inner.mode != outer.mode
|| inner.scheme != outer.scheme
|| !layout::is_safe_branch_path(path)
|| !matches!(inner.mode.as_str(), "100644" | "100755" | "120000")
{
bail!("encrypted file does not match its path or mode: {path}");
}
Ok(())
}
pub(crate) fn decrypt(
repo: &HistoryRepo,
path: &str,
object: &Object,
interactive: bool,
) -> Result<Object> {
let outer = envelope(repo, object, agecrypt::MAX_ENCRYPTED_BYTES)?
.ok_or_else(|| eyre::eyre!("missing encrypted file envelope: {path}"))?;
if control_file(path) {
bail!("setup configuration itself cannot be encrypted: {path}");
}
if outer.path != path {
bail!("encrypted file does not match its path: {path}");
}View on GitHub (pinned to afd2eddd3a)
Solutions
- Re-pull the encrypted store from origin (mise bootstrap dotfiles pull) to replace the corrupt envelope.
- Re-encrypt the file from its plaintext source so path/mode/scheme match consistently.
- Check the file's path is a safe branch path and its mode is a supported git mode (100644/100755/120000).
- If a merge caused the mismatch, resolve the encrypted file by taking one whole side, never hand-merging envelope bytes.
Example fix
// before: hand-merged envelope with mismatched inner path $ git checkout --theirs .config/secrets.env.enc // after: replace the whole envelope from a verified side $ git checkout origin/history -- .config/secrets.env.enc $ mise bootstrap dotfiles pull
Defensive patterns
Strategy: validation
Validate before calling
fn safe_to_decrypt(path: &str, mode: &str) -> bool {
layout::is_safe_branch_path(path)
&& matches!(mode, "100644" | "100755" | "120000")
} Try / catch
match decrypt(repo, &object, path, interactive) {
Ok(obj) => apply(obj),
Err(e) if e.to_string().contains("does not match its path or mode") => {
eprintln!("envelope integrity failed; re-pulling from origin");
repull_from_origin(path);
}
Err(e) => return Err(e),
} Prevention
- Never hand-edit or hand-merge encrypted envelope files; always resolve to one whole side.
- Re-encrypt (push) after renaming or moving encrypted files.
- Only track regular files, executables, and symlinks in encrypted sources.
- Verify store integrity (pull from origin) after restores or history rewrites.
When it happens
Trigger: Calling decrypt (via commit_object) on an encrypted blob whose inner Plaintext.path differs from the outer envelope path, whose inner mode/scheme differs from the outer, whose path fails layout::is_safe_branch_path, or whose mode is not 100644/100755/120000.
Common situations: Hand-edited or partially merged encrypted files in the setup store; an attacker or a bad tool rewriting the envelope metadata; a symlink or special file with an unsupported mode being encrypted; path renames done on only one side of the envelope.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- cannot synchronize: {reason}
- encrypted dotfile {target} requires an external source, not
- partial pulls are not supported: apply the complete setup wi
- save {} before choosing --keep-local
- sync paused: resolve all {} conflict(s) before sharing resum
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/6ed209277a0920ae.
Report an issue: GitHub.