{"record":{"id":"62de85644a878233","repo":"libnyanpasu/clash-nyanpasu","slug":"journal-destination-has-a-different-payload","errorCode":null,"errorMessage":"journal destination has a different payload","messagePattern":"journal destination has a different payload","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/service/profile_file.rs","lineNumber":1238,"sourceCode":"        root: &Path,\n        operation_id: &str,\n        from: JournalLocation,\n        to: JournalLocation,\n    ) -> anyhow::Result<()> {\n        let source = Self::journal_path(root, from, operation_id);\n        let destination = Self::journal_path(root, to, operation_id);\n        let source_journal = Self::read_journal(&source, operation_id)?;\n        match std::fs::symlink_metadata(&destination) {\n            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {\n                Self::advance_journal_phase(&source, &destination, &source_journal)\n            }\n            Ok(metadata) if is_symlink_or_reparse(&metadata) || !metadata.is_file() => bail!(\n                \"journal destination is not a regular file: {}\",\n                destination.display()\n            ),\n            Ok(_) => {\n                if Self::read_journal(&destination, operation_id)? != source_journal {\n                    bail!(\"journal destination has a different payload\");\n                }\n                Self::remove_private_regular(&source)\n            }\n            Err(error) => Err(error).context(\"inspect journal destination\"),\n        }\n    }\n\n    fn transition_cleanup_journal(\n        root: &Path,\n        operation_id: &str,\n        from: CleanupPhase,\n        to: CleanupPhase,\n    ) -> anyhow::Result<()> {\n        let source = Self::cleanup_path(root, from, operation_id);\n        let destination = Self::cleanup_path(root, to, operation_id);\n        let source_journal = Self::read_journal(&source, operation_id)?;\n        match std::fs::symlink_metadata(&destination) {\n            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {","sourceCodeStart":1220,"sourceCodeEnd":1256,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/service/profile_file.rs#L1220-L1256","documentation":"When transition_journal finds the destination phase journal already present as a regular file, it compares the destination journal's payload with the source journal's. If they differ, it bails instead of overwriting, because two journals with the same operation_id but different payloads indicate corrupted or interleaved transaction state. The library intentionally never silently discards either journal.","triggerScenarios":"Advancing a journal phase (e.g. staged -> committed for the same operation_id) when the destination already holds a journal written by a different operation/attempt that reused the same operation_id, or a partially-written/damaged journal whose contents no longer match.","commonSituations":"A crash left both phases populated but the Windows write-through path was interrupted mid-write leaving a torn payload; an operation_id was accidentally regenerated/reused across attempts; a user restored the journal directory from an old backup mixing attempts.","solutions":["Treat the operation as unrecoverable: delete all journal files for that operation_id (both phase locations) and re-run the profile operation from scratch.","Compare the two journal files at the printed paths to confirm which attempt is newer, and manually remove the stale one if you must salvage it.","Avoid reusing operation ids across attempts; ensure each materialization generates a fresh id.","If crashes cause this repeatedly, verify disk integrity (fsck/chkdsk) — torn writes suggest storage-level problems."],"exampleFix":"// before: retrying the transition always re-bails\ntransition_journal(root, &id, from, to)?;\n// after: discard the conflicting operation and start over\nfor loc in [from, to] {\n    let _ = std::fs::remove_file(journal_path(root, loc, &id));\n}\nlet prepared = prepare_materialization(...)?; // new operation_id\nprepared.commit()?;","handlingStrategy":"try-catch","validationCode":"fn journal_payloads_agree(root: &Path, from: JournalLocation, to: JournalLocation, id: &str) -> bool {\n    let (a, b) = (journal_path(root, from, id), journal_path(root, to, id));\n    match (std::fs::read(a), std::fs::read(b)) {\n        (Ok(a), Ok(b)) => a == b,\n        _ => true, // missing destination is fine; transition will create it\n    }\n}","typeGuard":null,"tryCatchPattern":"match transition_journal(root, id, from, to) {\n    Err(e) if e.to_string().contains(\"different payload\") => {\n        // ambiguous transaction: delete all journals for this operation_id and restart\n    }\n    other => other?,\n}","preventionTips":["Generate a fresh operation_id for every materialization attempt","Verify disk health if torn journal payloads recur after crashes","Do not restore journal directories from partial backups","Let recovery converge matching duplicates instead of editing journals by hand"],"tags":["filesystem","crash-recovery","transactional-journal","data-integrity"],"backgroundTag":"internal-invariant-violation","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}