{"record":{"id":"6ed209277a0920ae","repo":"jdx/mise","slug":"encrypted-file-does-not-match-its-path-or-mode-p","errorCode":null,"errorMessage":"encrypted file does not match its path or mode: {path}","messagePattern":"encrypted file does not match its path or mode: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/files.rs","lineNumber":241,"sourceCode":"    // Only encrypted envelopes have this limit; do not change plaintext sync.\n    let bytes = repo.cat_object_bounded(&object.1, limit)?;\n    let Some(body) = bytes.strip_prefix(MAGIC) else {\n        return Ok(None);\n    };\n    Ok(Some(\n        rmp_serde::from_slice(body).wrap_err(\"invalid encrypted file envelope\")?,\n    ))\n}\n\nfn validate(path: &str, outer: &Envelope, inner: &Plaintext) -> Result<()> {\n    if outer.path != path\n        || inner.path != path\n        || inner.mode != outer.mode\n        || inner.scheme != outer.scheme\n        || !layout::is_safe_branch_path(path)\n        || !matches!(inner.mode.as_str(), \"100644\" | \"100755\" | \"120000\")\n    {\n        bail!(\"encrypted file does not match its path or mode: {path}\");\n    }\n    Ok(())\n}\n\npub(crate) fn decrypt(\n    repo: &HistoryRepo,\n    path: &str,\n    object: &Object,\n    interactive: bool,\n) -> Result<Object> {\n    let outer = envelope(repo, object, agecrypt::MAX_ENCRYPTED_BYTES)?\n        .ok_or_else(|| eyre::eyre!(\"missing encrypted file envelope: {path}\"))?;\n    if control_file(path) {\n        bail!(\"setup configuration itself cannot be encrypted: {path}\");\n    }\n    if outer.path != path {\n        bail!(\"encrypted file does not match its path: {path}\");\n    }","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/sync/files.rs#L223-L259","documentation":"This validate() checks that an encrypted history blob is internally consistent: the inner plaintext header's path, mode, and scheme must match the outer envelope's, the path must be a safe branch path, and the mode must be a regular-file or symlink mode. If any of these disagree, the encrypted file has been tampered with, truncated, or produced by a mismatched writer, so mise rejects it with this error. It is called from decrypt before any decryption result is trusted.","triggerScenarios":"`decrypt` in files.rs calls validate on a history object and the envelope's inner header disagrees with the outer envelope or expectations: inner.path != requested path, inner.mode != outer.mode, inner.scheme != outer.scheme, path fails layout::is_safe_branch_path, or mode is not 100644/100755/120000.","commonSituations":"A history blob was manually edited or re-parented under a different path; an encryption scheme upgrade left mixed old/new envelopes; a corrupted or partially written blob in the history store; an unsafe path (e.g. traversal-like) smuggled into an envelope.","solutions":["Identify which history commit/object holds the mismatching blob (the path is in the message) and re-encrypt or drop that version from history.","Re-pull or re-push the affected file so a fresh, consistent envelope is written.","Check for manual edits to the history store and revert them; the envelope must never be hand-modified.","If caused by a scheme/tool upgrade, upgrade or downgrade mise so writer and reader agree on the envelope scheme."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# sanity-check the envelope for a tracked encrypted path before decrypting\nmise dot cat <path> >/dev/null || echo 'envelope inconsistent — re-encrypt or re-sync this path'","typeGuard":null,"tryCatchPattern":"if err.contains('does not match its path or mode') {\n    // blob is corrupt/tampered: re-encrypt from source of truth, do not trust decrypted output\n}","preventionTips":["Never hand-edit blobs in the history store.","Keep mise versions consistent across machines so envelope schemes match.","Re-push affected files after interrupted writes so envelopes are rewritten cleanly.","Verify paths stay within safe branch paths (no traversal-style names) when importing history."],"tags":["encryption","validation","integrity","sync"],"backgroundTag":"schema-validation-failed","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}