BigPizzaV3/CodexPlusPlus · error
Backups must be outside the cache
Error message
Backups must be outside the cache
What it means
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.
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.
Example fix
// before
let paths = BrowserPaths { runtime_root: cache_dir.clone(), state_root: cache_dir.join("codex-backups") };
reconcile(&paths, enabled)?; // Backups must be outside the cache
// after
let paths = BrowserPaths { runtime_root: cache_dir.clone(), state_root: app_data_dir.join("codex-native-browser-state") };
debug_assert!(!paths.state_root.starts_with(&paths.runtime_root));
reconcile(&paths, enabled)?; Defensive patterns
Strategy: validation
Validate before calling
fn validate_paths(paths: &BrowserPaths) -> Result<(), String> {
if paths.state_root.starts_with(&paths.runtime_root) {
Err("state_root (backups) must not be inside runtime_root".into())
} else { Ok(()) }
} Type guard
fn paths_are_safe(paths: &BrowserPaths) -> bool {
!paths.state_root.starts_with(&paths.runtime_root)
} Try / catch
match reconcile(&paths, enabled) {
Err(e) if e.to_string().contains("Backups must be outside the cache") => {
eprintln!("Fix BrowserPaths: move state_root out of {:?}", paths.runtime_root);
}
other => other?,
} Prevention
- 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
When it happens
Trigger: 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").
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- 请填写 API 的模型名称
- Codex CLI 路径指向的是目录而不是可执行文件:
- Codex CLI 路径不存在: 请填 Codex CLI 可执行文件的完整路径。macOS 桌面版通常在…
- 请输入完整的 HTTPS API 地址
- 主题包必须是 32 MiB 以内的普通 ZIP 文件
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/5cfa9eeca39e0e28.
Report an issue: GitHub.
Appendix: source
Thrown at crates/codex-plus-core/src/native_browser.rs:551
);
}
Ok(())
}
/// No runtime operation occurs when this feature has never been enabled.
/// Call only from the owning launcher, never from settings save or status inspection.
pub fn reconcile(paths: &BrowserPaths, enabled: bool) -> Result<BrowserStatus> {
reconcile_contract(paths, enabled, &RuntimeContract::pinned())
}
fn reconcile_contract(
paths: &BrowserPaths,
enabled: bool,
contract: &RuntimeContract,
) -> Result<BrowserStatus> {
plain_path(&paths.runtime_root)?;
plain_path(&paths.state_root)?;
ensure!(
!paths.state_root.starts_with(&paths.runtime_root),
"Backups must be outside the cache"
);
if !enabled && !paths.state_root.exists() {
return Ok(BrowserStatus::new("disabled", "Not configured"));
}
fs::create_dir_all(&paths.state_root)?;
let _guards = pin_parents(&paths.state_root.join("owner.lock"))?;
let lock_path = paths.state_root.join("owner.lock");
plain_path(&lock_path)?;
let lock = OpenOptions::new()
.create(true)
.truncate(false)
.write(true)
.open(lock_path)?;
lock.try_lock_exclusive()
.context("Another compatibility transaction is active")?;
let result = reconcile_locked(paths, enabled, contract);View on GitHub (pinned to b1ed92e5e4)