affaan-m/ECC · warning · anyhow::Error
Merge blocked between {left_branch} and {right_branch} by {}
Error message
Merge blocked between {left_branch} and {right_branch} by {} conflict(s): {detail} What it means
merge_into_base calls merge_readiness, and when the status is Conflicted it bails with `readiness.summary`. The summary string is the conflict report assembled by merge_readiness_for_branches (count of conflicts plus up to three path examples). This is a guarded refusal to perform a merge that git has already predicted will conflict.
Source
Thrown at ecc2/src/worktree/mod.rs:861
} else {
Ok(WorktreeHealth::InProgress)
}
}
pub fn has_uncommitted_changes(worktree: &WorktreeInfo) -> Result<bool> {
Ok(!git_status_short(&worktree.path)?.is_empty())
}
pub fn has_staged_changes(worktree: &WorktreeInfo) -> Result<bool> {
Ok(git_status_entries(worktree)?
.iter()
.any(|entry| entry.staged))
}
pub fn merge_into_base(worktree: &WorktreeInfo) -> Result<MergeOutcome> {
let readiness = merge_readiness(worktree)?;
if readiness.status == MergeReadinessStatus::Conflicted {
anyhow::bail!(readiness.summary);
}
if has_uncommitted_changes(worktree)? {
anyhow::bail!(
"Worktree {} has uncommitted changes; commit or discard them before merging",
worktree.branch
);
}
let repo_root = base_checkout_path(worktree)?;
let current_branch = get_current_branch(&repo_root)?;
if current_branch != worktree.base_branch {
anyhow::bail!(
"Base branch {} is not checked out in repo root (currently {})",
worktree.base_branch,
current_branch
);
}View on GitHub (pinned to 01e15490f0)
Solutions
- Rebase or manually resolve the conflicts before merging: `git -C <worktree> rebase <base>`.
- Use branch_conflict_preview to surface the conflicting paths to the user before they retry.
- After resolving, re-run merge_readiness to confirm status == Ready before calling merge_into_base.
- If the conflicts are spurious from stale refs, `git fetch` and re-derive readiness.
Example fix
// before
let outcome = merge_into_base(&worktree)?;
// after
let readiness = merge_readiness(&worktree)?;
if readiness.status == MergeReadinessStatus::Conflicted {
return Err(anyhow!("merge has {} conflict(s): {}",
readiness.conflicts.len(), readiness.conflicts.join(", ")));
}
let outcome = merge_into_base(&worktree)?; Defensive patterns
Strategy: validation
Validate before calling
use crate::worktree::{merge_readiness, MergeReadinessStatus};
let readiness = merge_readiness(&worktree)?;
if readiness.status == MergeReadinessStatus::Conflicted {
return Err(anyhow!(
"merge blocked by {} conflict(s): {}",
readiness.conflicts.len(),
readiness.conflicts.join(", ")
));
}
let outcome = merge_into_base(&worktree)?; Type guard
fn is_merge_ready(r: &MergeReadiness) -> bool {
r.status == MergeReadinessStatus::Ready
} Try / catch
match merge_into_base(&worktree) {
Ok(outcome) => Ok(outcome),
Err(e) => {
let m = format!("{e:#}");
if m.starts_with("Merge blocked") {
// surface the conflict list to the user; suggest rebase or manual resolve
}
Err(e)
}
} Prevention
- Always call `merge_readiness` before `merge_into_base` and gate the merge button on Ready.
- Rebase long-lived branches onto base regularly to shrink the conflict surface.
- Use `branch_conflict_preview` to show users the conflicting paths before they retry.
- After resolving conflicts, re-run `merge_readiness` to confirm Ready before retrying the merge.
When it happens
Trigger: Calling merge_into_base on a worktree branch whose merge-tree preview against base_branch produced conflict paths (both sides modified the same regions). The bail happens before any working-tree mutation, so the repo is left untouched.
Common situations: Long-lived feature branch behind a rebased main; two agents working in different worktrees edited the same files and one tries to merge first; auto-merge pipeline hitting a genuinely conflicting change set.
Related errors
- Cannot merge active session {} while it is {}
- selected hunk is already staged
- selected hunk is not staged
- cannot reset hunks for untracked files
- cannot reset a staged hunk while the file also has unstaged
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/91252282302b8b44.
Report an issue: GitHub.