{"record":{"id":"3e69d5796c6e2e10","repo":"BigPizzaV3/CodexPlusPlus","slug":"recovery-verification-failed","errorCode":null,"errorMessage":"Recovery verification failed","messagePattern":"Recovery verification failed","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/native_browser.rs","lineNumber":530,"sourceCode":"        ensure!(\n            current == original || current == candidate,\n            \"External runtime change prevents recovery\"\n        );\n        if current == candidate {\n            let modified = UNIX_EPOCH\n                .checked_add(Duration::new(journal.modified_secs, journal.modified_nanos))\n                .context(\"Invalid recovery timestamp\")?;\n            pending.push((target, modified, original, current));\n        }\n    }\n    // Preflight every cache before restoring any, independent of directory enumeration order.\n    for (target, modified, original, current) in pending {\n        ensure!(\n            read_regular(&target, MAX_SERVICE)? == current,\n            \"Concurrent recovery change\"\n        );\n        atomic_write_with_modified(&target, &original, Some(modified))?;\n        ensure!(\n            read_regular(&target, MAX_SERVICE)? == original,\n            \"Recovery verification failed\"\n        );\n    }\n    Ok(())\n}\n\n/// No runtime operation occurs when this feature has never been enabled.\n/// Call only from the owning launcher, never from settings save or status inspection.\npub fn reconcile(paths: &BrowserPaths, enabled: bool) -> Result<BrowserStatus> {\n    reconcile_contract(paths, enabled, &RuntimeContract::pinned())\n}\n\nfn reconcile_contract(\n    paths: &BrowserPaths,\n    enabled: bool,\n    contract: &RuntimeContract,\n) -> Result<BrowserStatus> {","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/native_browser.rs#L512-L548","documentation":"restore_all performs a prefetched, two-phase restore of the native browser service file in the runtime cache: it first collects all pending restorations, then for each one re-reads the file, atomically writes back the original content with the preserved mtime, and re-reads to verify. This ensure! fires when, immediately after the atomic write reported success, the file on disk does not equal the original bytes — i.e. the write-back did not durably land as expected. The library throws it as a fail-closed safety check because silently accepting an unrestored service file would leave a modified browser helper in place.","triggerScenarios":"restore_all (via reconcile_locked/reconcile on disable) after atomic_write_with_modified succeeds but a subsequent read_regular of the same target returns content != original. Concrete causes: another process (the browser itself or an antivirus) rewrote the file between the write and the verify read; the atomic rename was undone or intercepted; filesystem/caching anomalies where the rename is not yet visible to the read; or disk corruption of the freshly written file.","commonSituations":"Disabling native-browser compatibility while the browser is running and its service keeps rewriting its own file; antivirus or sync tools (OneDrive/Dropbox) holding or reverting files in the browser cache; a second CodexPlusPlus process racing the restore despite the owner lock; full disk or quota preventing a complete write.","solutions":["Close the browser (kill all its processes) so nothing rewrites the service file, then re-run reconcile(paths, false).","Exclude the browser runtime cache and the state_root backup directory from antivirus/backup/sync software, then retry.","Ensure only one launcher instance is running (the owner.lock holder); stop other instances and retry the restore.","Check free disk space and filesystem health (chkdsk); if the cache is corrupted, let the desktop app delete the affected browser cache so restore skips the obsolete runtime, then reinstall/repair the browser."],"exampleFix":"// before: restoring while the browser is running\nreconcile(&paths, false)?; // -> Recovery verification failed\n\n// after: shut down the browser first, then reconcile with retry\nassert!(wait_browser_closed(&paths));\nfor _ in 0..3 {\n    match reconcile(&paths, false) {\n        Ok(status) => { break; }\n        Err(e) if e.to_string().contains(\"Recovery verification failed\") => continue,\n        Err(e) => return Err(e),\n    }\n}","handlingStrategy":"retry","validationCode":"// Before restoring, ensure the browser is not holding/rewriting the file\nfn service_stable(paths: &BrowserPaths, key: &str) -> std::io::Result<bool> {\n    let target = paths.runtime_root.join(key).join(\"SERVICE\");\n    let a = std::fs::read(&target)?;\n    std::thread::sleep(std::time::Duration::from_millis(500));\n    Ok(std::fs::read(&target)? == a)\n}","typeGuard":null,"tryCatchPattern":"match reconcile(&paths, false) {\n    Err(e) if e.to_string().contains(\"Recovery verification failed\") => {\n        // browser/AV interference: close browser, add AV exclusion, retry with backoff\n        retry_with_backoff(3, || reconcile(&paths, false));\n    }\n    other => other?,\n}","preventionTips":["Always close the browser before disabling/ restoring native browser compatibility","Exclude the browser cache and state_root directories from antivirus, backup, and cloud-sync tools","Run only one launcher instance so the owner lock is uncontended","Keep sufficient free disk space and periodically check filesystem health"],"tags":["filesystem","atomic-write","verification-failed","windows","concurrency"],"backgroundTag":"file-write-failed","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}