{"record":{"id":"0780576794be5fa9","repo":"BigPizzaV3/CodexPlusPlus","slug":"native-browser-service-has-not-been-restored","errorCode":null,"errorMessage":"Native browser service has not been restored","messagePattern":"Native browser service has not been restored","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/native_browser.rs","lineNumber":712,"sourceCode":"        return Ok(());\n    }\n    let control = paths.state_root.join(\"control.json\");\n    if control.exists() {\n        let value: Value = serde_json::from_slice(&read_regular(&control, 1024)?)?;\n        ensure!(\n            value[\"schema\"] == 1 && value[\"requireIdentification\"] == false,\n            \"Native browser compatibility is still enabled\"\n        );\n    }\n    for entry in fs::read_dir(&paths.state_root)? {\n        let key = entry?.file_name().to_string_lossy().to_string();\n        if !key_valid(&key) || !paths.state_root.join(&key).join(\"journal.json\").exists() {\n            continue;\n        }\n        let target = paths.runtime_root.join(&key).join(SERVICE);\n        if target.exists() {\n            let (_, original, _) = recovery_material(paths, &key, &RuntimeContract::pinned())?;\n            ensure!(\n                read_regular(&target, MAX_SERVICE)? == original,\n                \"Native browser service has not been restored\"\n            );\n        }\n    }\n    Ok(())\n}\n\nfn acquire_monitor_owner(paths: &BrowserPaths) -> Result<File> {\n    plain_path(&paths.state_root)?;\n    ensure!(\n        !paths.state_root.starts_with(&paths.runtime_root),\n        \"Backups must be outside the cache\"\n    );\n    fs::create_dir_all(&paths.state_root)?;\n    let path = paths.state_root.join(\"monitor.lock\");\n    let _guards = pin_parents(&path)?;\n    let mut options = OpenOptions::new();","sourceCodeStart":694,"sourceCodeEnd":730,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/native_browser.rs#L694-L730","documentation":"verify_restored_state also checks every browser key that has recovery material (journal.json): if the corresponding runtime service file still exists, it must match the original bytes recovered from the backup. This ensure! fires when the runtime service file is present but differs from the original — meaning the modified/injected service was never reverted. The library throws it so callers cannot assume a clean shutdown while a patched helper is still deployed.","triggerScenarios":"wait_for_monitor_shutdown_at -> verify_restored_state when, for some key with journal.json, runtime_root/<key>/SERVICE exists and its content != the original recovered via recovery_material. Causes: restore_all never ran or failed for that key (e.g. an earlier 'External runtime change prevents recovery' or 'Recovery verification failed' abort), the browser re-modified the file after restore, or the journal's original no longer matches what the desktop app expects (contract/browser update changed the file).","commonSituations":"A previous failed disable left the modified helper in place and a later shutdown verify trips; the browser auto-updated and rewrote its service file between restore and verification; backup journal restored from an old state_root no longer matching the installed browser version.","solutions":["Run reconcile(&paths, false) (or reconcile_contract with the pinned contract) to perform a full restore_all pass, closing the browser first so it cannot rewrite the service file.","If recovery_material/journal no longer matches the browser version, update/repair the browser (or let the desktop app clear its cache) so the runtime file is regenerated from the pristine original, then re-verify.","Check diagnostic logs for the earlier restore failure (e.g. concurrent change, external modification) that left this key unrestored, fix that root cause (AV exclusion, single owner, browser closed), and retry."],"exampleFix":"// before\nmonitor.stop().await; // verify_restored_state -> \"service has not been restored\"\n\n// after\nclose_browser(&paths);\nmatch reconcile(&paths, false) {\n    Ok(status) => monitor.stop().await,\n    Err(e) => log::error!(\"restore failed: {e}\"),\n}","handlingStrategy":"validation","validationCode":"// Verify each journaled runtime service matches its original before relying on shutdown\nfn services_restored(paths: &BrowserPaths) -> anyhow::Result<bool> {\n    for entry in std::fs::read_dir(&paths.state_root)? {\n        let key = entry?.file_name().to_string_lossy().to_string();\n        let target = paths.runtime_root.join(&key).join(\"SERVICE\");\n        if target.exists() {\n            let (_, original, _) = recovery_material(paths, &key, &RuntimeContract::pinned())?;\n            if std::fs::read(&target)? != original { return Ok(false); }\n        }\n    }\n    Ok(true)\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = monitor.stop_and_verify().await {\n    if e.to_string().contains(\"has not been restored\") {\n        close_browser(&paths);\n        reconcile(&paths, false)?; // run the full restore pass, then re-verify\n    }\n}","preventionTips":["Close the browser before disabling so it cannot rewrite its service file after restore","Investigate and fix any earlier restore failure (external change / concurrent change) immediately instead of leaving the modified helper in place","After a browser update, run reconcile so recovery material is re-validated against the new runtime files","Do not restore old state_root snapshots that no longer match the installed browser version"],"tags":["restore","state-verification","filesystem","browser-integration"],"backgroundTag":"file-read-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"}