Hmbown/CodeWhale · critical
; ROLLBACK FAILED — the pre-import document is preserved at
Error message
{error:#}; ROLLBACK FAILED — the pre-import document is preserved at {} What it means
The most dangerous import outcome: the apply step failed AND the rollback also failed (rollback_import_target or store.reload() errored). The library raises the original error plus "ROLLBACK FAILED" and points at the backup file path where the pre-import document was preserved, so the user can restore manually.
Solutions
- Manually restore the pre-import document from the backup path printed in the error message.
- Check disk space and file permissions on the config location, fix them, and retry the import.
- Ensure no other process is holding the config file or the backup open/locked.
- After restoring, diff the live config against the backup to confirm state, then re-run the corrected import.
Example fix
// recovery cp ~/.config/codewhale/config.toml.bak ~/.config/codewhale/config.toml # then retry the import after fixing disk/permissions
Defensive patterns
Strategy: fallback
Validate before calling
// Before importing, verify the config dir is writable and has free space: // df -h ~/.config/codewhale && test -w ~/.config/codewhale/config.toml && echo ok
Try / catch
match run_import(&bundle, &store, scope) {
Err(e) if e.to_string().contains("ROLLBACK FAILED") => {
let backup = extract_backup_path(&e.to_string());
eprintln!("restore manually: cp {backup:?} <config path>, then diff before retrying");
}
other => other?,
} Prevention
- Ensure ample disk space and write permissions on the config directory before imports.
- Never delete or lock the .bak backup files the importer creates.
- Close other processes that hold the config file open during import.
- After any failed import, diff the live config against the backup to verify state.
When it happens
Trigger: apply(candidate, ...) errors during apply_bundle/run_import, then rollback_import_target (restoring the backup or deleting a config created during the transaction) or store.reload() also fails — e.g. the backup path is gone, the disk is full, or the config file is locked/read-only.
Common situations: Disk-full or permission problems preventing the backup restore; another process deleting the backup mid-import; the target config file made read-only by another tool; a config created during the transaction that could not be removed.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- ; rolled back to the pre-import document
- bundle carries [project] entries; import it with --project…
- bundle contains conflicting or rejected entries
- could not release root config policy
- A managed, project or plugin connector already uses this…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/37c948af254e09b9.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/config_bundles.rs:1091
let original_config = store.config.clone();
let backup_path = if target
.try_exists()
.with_context(|| format!("checking config target {}", target.display()))?
{
Some(create_collision_safe_backup(&target)?)
} else {
None
};
let mut target_written = false;
let apply_result = apply(candidate, store, &mut target_written);
if let Err(error) = apply_result {
store.config = original_config;
let rollback = rollback_import_target(&target, backup_path.as_deref(), target_written)
.and_then(|()| store.reload());
match rollback {
Ok(()) => bail!("{error:#}; rolled back to the pre-import document"),
Err(_) => bail!(
"{error:#}; ROLLBACK FAILED — the pre-import document is preserved at {}",
backup_path
.as_deref()
.map(Path::display)
.map(|path| path.to_string())
.unwrap_or_else(
|| "<no prior file; remove the new target manually>".to_string()
)
),
}
}
Ok(ImportReceipt {
plan,
backup_path,
target,
})
}View on GitHub (pinned to 73e0f67d83)