{"record":{"id":"0715b324e3c537f2","repo":"BigPizzaV3/CodexPlusPlus","slug":"restore-conflict-file-already-exists-path","errorCode":null,"errorMessage":"restore conflict: file already exists: {path}","messagePattern":"restore conflict: file already exists: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-data/src/storage.rs","lineNumber":1101,"sourceCode":"            .map(|(key, _)| vec![key])\n            .unwrap_or_default()\n    } else {\n        keys\n    }\n}\n\nfn detect_file_restore_conflicts(tables: &Map<String, Value>) -> anyhow::Result<()> {\n    let Some(files) = tables.get(\"__files\").and_then(Value::as_array) else {\n        return Ok(());\n    };\n    let allowed_paths = allowed_backup_file_paths(tables);\n    for file in files {\n        if let Some(path) = file.get(\"path\").and_then(Value::as_str) {\n            if !allowed_paths.contains(path) {\n                anyhow::bail!(\"unexpected backup file path: {path}\");\n            }\n            if Path::new(path).exists() {\n                anyhow::bail!(\"restore conflict: file already exists: {path}\");\n            }\n            if let Some(content) = file.get(\"content_b64\").and_then(Value::as_str) {\n                base64::Engine::decode(&base64::engine::general_purpose::STANDARD, content)?;\n            }\n        }\n    }\n    Ok(())\n}\n\nfn allowed_backup_file_paths(tables: &Map<String, Value>) -> HashSet<String> {\n    tables\n        .get(\"threads\")\n        .and_then(Value::as_array)\n        .into_iter()\n        .flatten()\n        .filter_map(|row| row.get(\"rollout_path\").and_then(Value::as_str))\n        .filter(|path| !path.trim().is_empty())\n        .map(ToString::to_string)","sourceCodeStart":1083,"sourceCodeEnd":1119,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/f2074595a281bc057525c748175c8eb9805b0673/crates/codex-plus-data/src/storage.rs#L1083-L1119","documentation":"Thrown by detect_file_restore_conflicts when an allowed backup file path already exists on disk — the rollback would overwrite a live rollout file. Mirrors the row-conflict policy (never clobber current data); the offending input is the existing file at {path}, and the undo aborts before writing any file.","triggerScenarios":"Thrown at crates/codex-plus-data/src/storage.rs:1101 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["确认是否在重复执行 undo（文件已恢复过一次）","先手动备份并移除冲突的现存文件再重试恢复","若现存文件是较新的会话数据，评估是否真的需要覆盖式恢复","在 UI 明确提示冲突文件路径供用户决策"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"f2074595a281bc057525c748175c8eb9805b0673","analyzedAt":"2026-08-23T12:52:24.489Z","contentChangedAt":"2026-08-23T12:52:24.489Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}