{"record":{"id":"98364e2154681be5","repo":"libnyanpasu/clash-nyanpasu","slug":"active-materialization-target-diverged-before-reco","errorCode":null,"errorMessage":"active materialization target diverged before recovery","messagePattern":"active materialization target diverged before recovery","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/service/profile_file.rs","lineNumber":1885,"sourceCode":"                        if active {\n                            match actual_location {\n                                JournalLocation::StatePrepared\n                                | JournalLocation::StatePromoting => {\n                                    if target_matches {\n                                        if actual_location == JournalLocation::StatePromoting {\n                                            self.complete(&prepared)?;\n                                            return Ok((0, 0, 1, 0));\n                                        }\n                                        Self::discard_materialization(\n                                            &root,\n                                            &operation_id,\n                                            actual_location,\n                                        )?;\n                                        return Ok((1, 0, 0, 0));\n                                    }\n                                    if !Self::target_is_pre_promote(&root, &operation_id, &target)?\n                                    {\n                                        bail!(\n                                            \"active materialization target diverged before recovery\"\n                                        );\n                                    }\n                                    // revision advanced past this journal while the target is\n                                    // still pre-promote: the transaction was superseded or\n                                    // rolled back. Compensate instead of applying stale staged\n                                    // content onto a newer committed profile revision.\n                                    self.compensate(&prepared)?;\n                                    return Ok((0, 0, 0, 1));\n                                }\n                                JournalLocation::FilePrepared if target_matches => {\n                                    self.promote(&prepared)?;\n                                    self.complete(&prepared)?;\n                                    return Ok((0, 0, 1, 0));\n                                }\n                                JournalLocation::FilePromoting | JournalLocation::FilePromoted\n                                    if target_matches =>\n                                {","sourceCodeStart":1867,"sourceCodeEnd":1903,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/service/profile_file.rs#L1867-L1903","documentation":"During recovery of a materialization transaction, the code checks whether revision counters advanced past the journaled revision while the target file is still in its pre-promote state. If the target hash differs from what the journal recorded for the pre-promote state (target_is_pre_promote fails), the on-disk state is inconsistent with any journaled history — the transaction was superseded, rolled back, or someone edited the file — and recovery bails with this error instead of applying a stale staged file over diverged content.","triggerScenarios":"Running recovery (e.g. on startup after a crash) for an operation whose journal revision is older than the current revision, when target_is_pre_promote(&root, &operation_id, &target) returns false — i.e. the current content of the managed target is neither the staged/promoted content nor the recorded pre-promote content.","commonSituations":"The profile file was hand-edited or modified by another tool between the crash and recovery; a second transaction already applied and advanced the revision while the journal of the first was left behind; a partial promote/crash left mixed state on disk.","solutions":["Inspect the operation journal and the managed path; if the current content is valid, discard the stale journal (remove operation artifacts) so recovery no longer tries to apply it","Re-run recovery after restoring the target to the expected pre-promote content (e.g. from the backup recorded in the journal) if stale application is acceptable","Trigger compensation for the superseded operation instead of forward recovery","Fix the writer that mutates the target without bumping the revision/creating its own journal to prevent future divergence"],"exampleFix":"// before: recovery crashes on diverged target\nrecovery.recover_stale_operations()?;\n// after: drop superseded journals whose target diverged\nfor op in recovery.stale_operations() {\n    if recovery.revision_advanced_past(&op) && !recovery.target_is_pre_promote(&op) {\n        recovery.discard_journal(op.id)?;\n    } else {\n        recovery.recover(&op)?;\n    }\n}","handlingStrategy":"validation","validationCode":"if recovery.revision_past(&op) && !recovery.target_pre_promote(&op)? {\n    // superseded/diverged: discard journal instead of recovering\n    recovery.discard_journal(&op.id)?;\n} else {\n    recovery.recover(&op)?;\n}","typeGuard":null,"tryCatchPattern":"match recovery.recover_stale_operations() {\n    Err(e) if e.to_string().contains(\"diverged before recovery\") => {\n        // do not retry; inspect and drop the stale journal or compensate\n        inspect_and_resolve_stale_journal()?;\n    }\n    other => other?,\n}","preventionTips":["Never edit managed target files outside the transaction framework","Ensure every writer bumps the revision and creates its own journal","Run recovery promptly after a crash, before other tools touch the profile directory","Compensate superseded operations instead of leaving stale journals behind"],"tags":["transaction","recovery","crash","file-conflict"],"backgroundTag":"invalid-state-transition","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}