gitbutlerapp/gitbutler · warning · ExplainedRejection
return anyhow::Error::new(ExplainedRejection(format!
Error message
return anyhow::Error::new(ExplainedRejection(format!("Cannot {verb}: {rejected}"))) What it means
When explaining why changes were rejected (`explain_after_rollback`), the workspace and database must be loaded to produce a dependency report. If that load fails, the function falls back to a minimal `ExplainedRejection` containing only the verb and rejection count — the explanation is degraded but the original failure is never masked.
Solutions
- Treat the message as a count-only explanation and inspect the earlier root-cause error alongside it.
- Check for and clear stale locks on the project database / workspace files.
- Re-open or re-initialize the project in GitButler to rebuild the workspace state.
- Enable tracing output — the load failure is logged with `tracing::warn!(?load_err, ...)`; use that error to fix the underlying cause.
Defensive patterns
Strategy: fallback
Try / catch
// consume the ExplainedRejection but keep the degraded message
match op().await {
Err(e) => {
let msg = e.to_string();
if msg.starts_with("Cannot ") { log::warn!("explanation degraded: {msg}"); }
Err(e)
}
ok => ok,
} Prevention
- Avoid running multiple processes against the same project database.
- Ensure clean shutdown so workspace state is never left half-written.
- Check tracing warnings ('Failed to load workspace to explain rejections') for the root cause.
When it happens
Trigger: Calling the post-rollback explanation path when `ctx.workspace_and_db_with_perm` fails, e.g. the workspace state on disk is corrupt/locked, the database cannot be opened, or the read permission is unavailable at that moment.
Common situations: A crashed prior run left the workspace data in a bad state; the project database file is locked by another process; repository moved/deleted between the operation and the explanation; permission degradation during shutdown.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- BUG: failed to apply head ref
- Cannot
- Cannot : :\n
- a committed transaction always materializes a workspace
- Ad-hoc (single-branch) branch moves are not supported…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/e5d24f06d440825d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/utils/rejection.rs:100
pub fn explain_after_rollback(
ctx: &Context,
perm: &mut RepoExclusive,
verb: &str,
target: Target,
err: anyhow::Error,
) -> anyhow::Error {
let rejected = match err.downcast::<RejectedChanges>() {
Ok(rejected) => rejected,
Err(other) => return other,
};
// Explaining a failure must never mask it: without a workspace projection,
// fall back to the plain rejection count.
let (repo, ws, _db) = match ctx.workspace_and_db_with_perm(perm.read_permission()) {
Ok(loaded) => loaded,
Err(load_err) => {
tracing::warn!(?load_err, "Failed to load workspace to explain rejections");
return anyhow::Error::new(ExplainedRejection(format!("Cannot {verb}: {rejected}")));
}
};
let (repo, ws) = (&repo, &ws);
let target_branch = match &target {
Target::Commit(commit) => branch_of_commit(ws, commit.commit_id, None),
Target::Branch(name) => Some(name.clone()),
Target::NewBranch(_) => None,
};
let changes = match explain_rejections(repo, ws, &rejected.0, target_branch.as_deref()) {
Ok(changes) => changes,
Err(other) => return other,
};
let mut message = format!("Cannot {verb}: {rejected}:\n");
// Writing to a String cannot fail.
let _ = write_report(&mut message, &changes, &target, target_branch.as_deref());View on GitHub (pinned to 58e5313667)