jdx/mise · error
encrypted file does not match its path
Error message
encrypted file does not match its path: {path} What it means
Thrown by `decrypt` when the path recorded inside the encrypted envelope (`outer.path`) does not match the path at which the encrypted file was actually found. The envelope is tamper-evident: each encrypted object is bound to its declared destination path, so a mismatch means the file was moved, renamed, or pointed at the wrong location.
Solutions
- Re-encrypt the file at its new path so the envelope records the correct destination.
- Move the file back to the path recorded in the envelope.
- Restore the file from history if it was accidentally renamed or copied.
Example fix
// before: manually moving the encrypted file mv ~/.config/encrypted-file.bin ~/.config/renamed.bin // after: re-sync so the envelope is rewritten for the new path mise setup sync // re-encrypts at the correct path
Defensive patterns
Strategy: validation
Validate before calling
// verify the envelope's recorded path before decrypting
const envelope = await sync.inspectEnvelope(path);
if (envelope.path !== path) {
throw new Error(`re-encrypt ${path}: envelope declares ${envelope.path}`);
} Type guard
function envelopeMatchesPath(envelope: { path: string }, path: string): envelope is { path: string } {
return envelope.path === path;
} Try / catch
try {
await sync.decrypt(path);
} catch (e) {
if (/does not match its path/.test(String(e))) {
await sync.encryptAt(path); // re-encrypt to bind the new path
} else throw e;
} Prevention
- Never move or rename encrypted files directly on disk; use the sync tool.
- Re-encrypt after any rename so the envelope path stays in sync.
- Don't copy ciphertext blobs between paths.
When it happens
Trigger: Calling `decrypt` (via `commit_object`) on a file whose decrypted `Plaintext.path` differs from the `path` argument — e.g. after `git mv`/manual rename of an encrypted file without re-encrypting, or copying an encrypted blob to another path.
Common situations: Renaming or relocating an encrypted dotfile on disk directly; symlinking one encrypted file at another path; merging histories where the same ciphertext landed at a different path.
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
- encrypted file does not match its path or mode
- artifact target has changed
- base image has layers in its manifest but diff_ids in its…
- base image has layers in its manifest but diff_ids in its…
- blob digest mismatch: got
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/15b90ebf5e487ee1.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/sync/files.rs:258
{
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}");
}
if let Some(decrypted) = repo.decrypted_object(&object.1) {
return Ok(decrypted);
}
let bytes = agecrypt::decrypt_sync(&outer.ciphertext.0, interactive).wrap_err_with(|| {
format!(
"cannot unlock {path}; run mise dot pull interactively with a matching age identity"
)
})?;
let inner: Plaintext =
rmp_serde::from_slice(&bytes).wrap_err("invalid encrypted file payload")?;
validate(path, &outer, &inner)?;
let oid = repo.transient_blob_id(&inner.content.0)?;
let decrypted = (inner.mode, oid);
repo.remember_decrypted(&object.1, decrypted.clone());
Ok(decrypted)
}
View on GitHub (pinned to 533346cc37)