{"record":{"id":"5cfa9eeca39e0e28","repo":"BigPizzaV3/CodexPlusPlus","slug":"backups-must-be-outside-the-cache","errorCode":null,"errorMessage":"Backups must be outside the cache","messagePattern":"Backups must be outside the cache","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/native_browser.rs","lineNumber":551,"sourceCode":"        );\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> {\n    plain_path(&paths.runtime_root)?;\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    if !enabled && !paths.state_root.exists() {\n        return Ok(BrowserStatus::new(\"disabled\", \"Not configured\"));\n    }\n    fs::create_dir_all(&paths.state_root)?;\n    let _guards = pin_parents(&paths.state_root.join(\"owner.lock\"))?;\n    let lock_path = paths.state_root.join(\"owner.lock\");\n    plain_path(&lock_path)?;\n    let lock = OpenOptions::new()\n        .create(true)\n        .truncate(false)\n        .write(true)\n        .open(lock_path)?;\n    lock.try_lock_exclusive()\n        .context(\"Another compatibility transaction is active\")?;\n    let result = reconcile_locked(paths, enabled, contract);","sourceCodeStart":533,"sourceCodeEnd":569,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/native_browser.rs#L533-L569","documentation":"reconc_contract validates the caller-supplied BrowserPaths before doing any work: the backup/state directory (state_root) must not be located inside the runtime cache directory (runtime_root). If the backups lived inside the cache, restoring the service or the desktop app clearing the cache could destroy or resurrect the backup material itself. The library therefore refuses such a configuration up front with this error.","triggerScenarios":"Calling reconcile(paths, enabled) (or any of its callers: monitor_once, tests) with a BrowserPaths whose state_root path string starts with runtime_root, e.g. state_root = runtime_root.join(\"backups\").","commonSituations":"Hand-constructing BrowserPaths for testing or custom setups and nesting the backup folder under the browser's cache/profile directory; a misconfigured environment variable or config pointing the state dir inside the browser profile; migrating paths and accidentally making state_root a subdirectory of runtime_root.","solutions":["Move state_root (the backup/state directory) outside runtime_root — e.g. a sibling directory or an app-data location — and construct BrowserPaths with the corrected paths.","If state_root was created inside runtime_root in a previous run, relocate the existing backup data to the new location before calling reconcile.","Add a startup check that validates !state_root.starts_with(runtime_root) whenever BrowserPaths is built from user config, failing fast with a clear message."],"exampleFix":"// before\nlet paths = BrowserPaths { runtime_root: cache_dir.clone(), state_root: cache_dir.join(\"codex-backups\") };\nreconcile(&paths, enabled)?; // Backups must be outside the cache\n\n// after\nlet paths = BrowserPaths { runtime_root: cache_dir.clone(), state_root: app_data_dir.join(\"codex-native-browser-state\") };\ndebug_assert!(!paths.state_root.starts_with(&paths.runtime_root));\nreconcile(&paths, enabled)?;","handlingStrategy":"validation","validationCode":"fn validate_paths(paths: &BrowserPaths) -> Result<(), String> {\n    if paths.state_root.starts_with(&paths.runtime_root) {\n        Err(\"state_root (backups) must not be inside runtime_root\".into())\n    } else { Ok(()) }\n}","typeGuard":"fn paths_are_safe(paths: &BrowserPaths) -> bool {\n    !paths.state_root.starts_with(&paths.runtime_root)\n}","tryCatchPattern":"match reconcile(&paths, enabled) {\n    Err(e) if e.to_string().contains(\"Backups must be outside the cache\") => {\n        eprintln!(\"Fix BrowserPaths: move state_root out of {:?}\", paths.runtime_root);\n    }\n    other => other?,\n}","preventionTips":["Always construct BrowserPaths with state_root as a sibling of, or entirely separate from, runtime_root","Validate path nesting whenever paths come from user config or environment variables","Never default the backup directory into the browser profile/cache folder","Add an assert/debug check in test helpers that build BrowserPaths"],"tags":["configuration","paths","validation","backup-safety"],"backgroundTag":"invalid-argument-value","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"}