Hmbown/CodeWhale · error
; rolled back to the pre-import document
Error message
{error:#}; rolled back to the pre-import document What it means
During apply_prepared_bundle, if the apply callback fails, the library rolls back: it restores the in-memory original config and attempts rollback_import_target plus store.reload(). If rollback succeeds, the original apply error is re-raised with the suffix "; rolled back to the pre-import document", telling the user the import failed atomically and nothing was changed.
Solutions
- Read the leading part of the message ({error:#}) — that is the real cause; fix it in the bundle.
- Retry the import after correcting the bundle; the pre-import document is intact so no manual restore is needed.
- Dry-run the import first to catch plan-level problems before apply.
- If the cause is a concurrent edit, re-read the current config and re-attempt when no other process is editing.
Example fix
// before apply = writes invalid provider slot -> Err -> rolled back // after dry-run import first, fix the offending bundle entry, then apply cleanly
Defensive patterns
Strategy: try-catch
Try / catch
match run_import(&bundle, &store, scope) {
Err(e) if e.to_string().ends_with("rolled back to the pre-import document") => {
// safe: nothing changed; fix the root cause (prefix of the message) and retry
eprintln!("import failed cleanly: {e:#}");
}
other => other?,
} Prevention
- Dry-run first so apply-stage failures are caught before any write attempt.
- Fix the root cause in the leading part of the message, not the rollback suffix.
- Avoid concurrent edits while importing; ConfigStore CAS rejects racing writes.
When it happens
Trigger: The user-supplied apply callback (or CAS-guarded store write) returns Err during run_import/apply_bundle; rollback of the target file and store reload both succeed, so this compound error is raised instead of the bare apply error.
Common situations: Importing a bundle whose values fail downstream validation in the apply step (e.g. invalid provider slot overrides); a CAS conflict with a concurrent editor that surfaced mid-apply; a migration callback erroring during route import.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- ; ROLLBACK FAILED — the pre-import document is preserved at
- 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/b2247df6d3429be1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/config_bundles.rs:1090
let target = store.path().to_path_buf();
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)