{"record":{"id":"a43df99b77b88007","repo":"tinyhumansai/openhuman","slug":"err-rollback-from-to-also-failed-restor","errorCode":null,"errorMessage":"{err}; rollback from {} to {} also failed: {restore_err}","messagePattern":"(.+?); rollback from (.+?) to (.+?) also failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/runtime/python/extractor.rs","lineNumber":95,"sourceCode":"                    final_dest.display(),\n                    candidate.display()\n                )\n            })?;\n            Some(candidate)\n        } else {\n            None\n        };\n\n        if let Err(err) = fs::rename(&staged, &final_dest).with_context(|| {\n            format!(\n                \"renaming staged {} -> {}\",\n                staged.display(),\n                final_dest.display()\n            )\n        }) {\n            if let Some(backup_path) = backup.as_ref() {\n                if let Err(restore_err) = fs::rename(backup_path, &final_dest) {\n                    return Err(anyhow!(\n                        \"{err}; rollback from {} to {} also failed: {restore_err}\",\n                        backup_path.display(),\n                        final_dest.display()\n                    ));\n                }\n            }\n            return Err(err);\n        }\n\n        if let Some(backup_path) = backup {\n            let _ = fs::remove_dir_all(backup_path);\n        }\n\n        Ok(final_dest)\n    })\n    .await\n    .context(\"spawn_blocking join failure during atomic install\")?\n}","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/runtime/python/extractor.rs#L77-L113","documentation":"Wraps a doubly-failed atomic-install: fs::rename of the staged Python distribution onto final_dest failed (context: 'renaming staged X -> Y'), and the best-effort rollback — renaming the backed-up previous installation back to final_dest — failed too. The error text chains the original cause and the restore failure. This leaves the user's Python install directory in a broken state (previous runtime moved aside, new one not installed), so it is escalated instead of swallowed. Typical causes: cross-filesystem rename, files locked by a running process (Windows), or permission problems.","triggerScenarios":"Thrown at src/openhuman/runtime/python/extractor.rs:95 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Manually inspect final_dest and the backup path; restore or delete whichever is left in place.","Ensure no process is holding files under the destination open (running REPLs, spawned children) and retry the install.","Ensure staged dir and destination are on the same filesystem, or switch to copy+delete instead of rename.","Re-run the installation after fixing permissions on the runtime directory."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}