jdx/mise · error

encrypted file does not match its path: {path}

Error message

encrypted file does not match its path: {path}

What it means

The outer encrypted envelope records the logical path of the file it protects. If the envelope's embedded path does not equal the path at which the object was found, decrypt() rejects it, because decrypting would place contents under an identity that does not match the store's record. This prevents path-swap attacks and accidental misplacement.

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 bootstrap dotfiles 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)
}

fn encrypt(
    repo: &HistoryRepo,
    path: &str,

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Re-encrypt the file at its new path so the envelope path matches (run the encrypt step of the dotfiles sync).
  2. Move the file back to its original path, or restore it from origin.
  3. Run mise bootstrap dotfiles pull to resync envelopes with the authoritative history.

Example fix

// before: envelope for ~/.gitconfig placed at ~/.gitconfig.bak
$ git mv ~/.gitconfig ~/.gitconfig.bak
// after: re-encrypt under the new path so outer.path matches
$ mise bootstrap dotfiles push  # re-encrypts and records the new path
Defensive patterns

Strategy: validation

Validate before calling

if envelope_path_for(blob) != target_path {
    eprintln!("re-encrypt needed: envelope path mismatch");
}

Try / catch

match decrypt(repo, &object, path, interactive) {
    Ok(obj) => obj,
    Err(e) if e.to_string().contains("does not match its path") => {
        eprintln!("{path} was moved; re-encrypting under new path");
        reencrypt(path)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling decrypt (via commit_object) on an object whose envelope(outer.path) differs from the requested path — e.g. the file was moved/renamed without re-encrypting, or envelope bytes were copied to another path.

Common situations: git mv on an encrypted file without re-encryption; cherry-pick/merge that relocated an encrypted blob; manually copying an .enc file to a new name.

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


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/15b90ebf5e487ee1. Report an issue: GitHub.