{"record":{"id":"4ec3097f6e7cec90","repo":"Hmbown/CodeWhale","slug":"error-runtime-preset-rollback-also-failed","errorCode":null,"errorMessage":"{error:#}; runtime preset rollback also failed: {}","messagePattern":"(.+?); runtime preset rollback also failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/ui.rs","lineNumber":2946,"sourceCode":"                }\n            },\n        }\n    }\n}\n\nfn runtime_preset_error_with_rollback(\n    error: anyhow::Error,\n    snapshots: &[&RuntimePresetFileSnapshot],\n) -> anyhow::Error {\n    let rollback_errors = snapshots\n        .iter()\n        .filter_map(|snapshot| snapshot.restore().err())\n        .map(|error| format!(\"{error:#}\"))\n        .collect::<Vec<_>>();\n    if rollback_errors.is_empty() {\n        error\n    } else {\n        anyhow::anyhow!(\n            \"{error:#}; runtime preset rollback also failed: {}\",\n            rollback_errors.join(\"; \")\n        )\n    }\n}\n\nfn mark_active_turn_cancelled_locally(app: &mut App) {\n    // #2739: every local cancel surface (Esc, Ctrl+C, approval abort, paused\n    // command abort) must snapshot before it clears turn state. Otherwise\n    // --continue reloads the previous save and the interrupted turn vanishes.\n    app.streaming_state.reset();\n    app.finalize_active_cell_as_interrupted();\n    app.finalize_streaming_assistant_as_interrupted();\n    persist_recovery_snapshot(app);\n    app.is_loading = false;\n    app.dispatch_started_at = None;\n    app.turn_started_at = None;\n    app.turn_last_activity_at = None;","sourceCodeStart":2928,"sourceCodeEnd":2964,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/tui/ui.rs#L2928-L2964","documentation":"runtime_preset_error_with_rollback reports a double failure: applying a runtime preset failed AND the automatic rollback that restores each RuntimePresetFileSnapshot (prior file contents) also failed. The combined message joins the original apply error with every rollback failure, which means preset files may be left in a partially written state - neither the new preset nor the old contents.","triggerScenarios":"A preset apply writes config files and hits I/O errors (permission denied, read-only mount, disk full, locked files); snapshot.restore() then fails on the same files for the same underlying reason, so rollback_errors is non-empty and both errors are merged.","commonSituations":"Preset files in a read-only dotfiles checkout or owned by root; disk full mid-write; files locked by a sync client (Dropbox/iCloud) mid-apply; permissions changed between snapshot and restore.","solutions":["Read the message in two parts: the text before '; runtime preset rollback also failed' is the original apply error - fix that root cause (permissions, disk space, locks)","Inspect every file named after 'rollback also failed' and reconcile its contents with your VCS or backup - do not assume the old values survived","chmod u+w the preset files (or remount read-write), free disk space, pause sync clients, then re-apply the preset","If the files are externally managed (dotfiles), remove them from the managed set or grant the TUI write access"],"exampleFix":"# before: preset file not writable\n$ ls -l ~/.codewhale/runtime-presets/\n-r--r--r-- 1 root root preset.json   # apply fails AND rollback fails\n\n# after\n$ sudo chown $USER ~/.codewhale/runtime-presets/* && chmod u+w ~/.codewhale/runtime-presets/*\n# re-apply the preset","handlingStrategy":"try-catch","validationCode":"// Rust - verify preset snapshot targets are writable before applying\nuse std::os::unix::fs::PermissionsExt;\nfn preset_paths_writable(paths: &[std::path::PathBuf]) -> bool {\n    paths.iter().all(|p| match std::fs::metadata(p) {\n        Ok(m) => m.permissions().mode() & 0o200 != 0,\n        Err(_) => p.parent().map(|d| d.is_dir()).unwrap_or(false),\n    })\n}","typeGuard":null,"tryCatchPattern":"match apply_runtime_preset(&preset, &snapshots) {\n    Err(e) => {\n        let combined = runtime_preset_error_with_rollback(e, &snapshots);\n        alert_and_reconcile_files(&combined); // rollback may have failed: verify file contents against snapshots/VCS\n    }\n    Ok(()) => (),\n}","preventionTips":["Pre-flight writability of every file a preset will touch","Keep preset files out of read-only mounts and sync-client directories during apply","After this error, always diff affected files against snapshots or VCS before retrying"],"tags":["config","preset","rollback","io","atomic-write"],"backgroundTag":"config-rollback-failed","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}