gastownhall/beads · warning
conflict for %s %s was not cleared (no conflict row deleted)
Error message
conflict for %s %s was not cleared (no conflict row deleted)
What it means
After issuing the DELETE on dolt_conflicts_<table>, this fires when RowsAffected reports 0 — the conflict row asked for no longer exists. Rather than reporting success for a conflict it did not actually clear, the code aborts so the caller knows the resolution was a no-op.
Source
Thrown at internal/storage/versioncontrolops/conflicts.go:435
// only when the row really is gone.
if n, err := res.RowsAffected(); err != nil || n == 0 {
present, err := conflictTargetStillPresent(ctx, db, table, keyCol, ourKey)
if err != nil {
return fmt.Errorf("confirm %s %s still exists after writing their values: %w", table, key, err)
}
if !present {
return fmt.Errorf("their values for %s %s matched no row (was it deleted concurrently?); conflict left unresolved", table, key)
}
}
}
del := fmt.Sprintf("DELETE FROM `dolt_conflicts_%s` WHERE `our_%s` = ?", table, keyCol) //nolint:gosec // identifiers validated
res, err := db.ExecContext(ctx, del, ourKey)
if err != nil {
return fmt.Errorf("clear conflict for %s %s: %w", table, key, err)
}
if n, err := res.RowsAffected(); err == nil && n == 0 {
return fmt.Errorf("conflict for %s %s was not cleared (no conflict row deleted)", table, key)
}
return nil
}
// GetMergeBlockers reports the merge state that `bd conflicts` cannot show as
// rows: whether a merge is open at all, plus the schema conflicts and
// constraint violations that make dolt refuse the merge commit even when
// every dolt_conflicts row is resolved (wy-36ilm F12). Without it, that state
// surfaced only as a raw dolt error from CommitMergeResolution, after the
// operator had been told "0 conflicts remain".
//
// Each source is read independently and a MISSING source table is not an
// error: dolt_schema_conflicts and dolt_constraint_violations are dolt system
// tables whose presence has varied across versions, and a diagnosis helper
// must never be the thing that fails the command.
func GetMergeBlockers(ctx context.Context, db DBConn) (storage.MergeBlockers, error) {
var out storage.MergeBlockers
var errs []errorView on GitHub (pinned to 71377f2769)
Solutions
- Re-query dolt_conflicts_<table> for the current conflict set; the row is already resolved, so treat this as success and continue.
- Run resolution to completion in one pass without interleaving other resolution invocations on the same branch.
- If the conflict reappeared (merge restarted), re-run the merge/pull to refresh the conflict table and resolve the new rows.
- Deduplicate concurrent resolvers (single session/lock) so only one process deletes conflict rows.
Example fix
// before: resolving keys captured long ago err := ops.ResolveConflictRows(ctx, db, "issues", "theirs", staleKeys) // after: refresh the conflict set first rows := listCurrentConflicts(ctx, db, "issues") // SELECT our_id FROM dolt_conflicts_issues err = ops.ResolveConflictRows(ctx, db, "issues", "theirs", keysOf(rows))
Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm the conflict row still exists before resolving:
var n int
_ = db.QueryRowContext(ctx, "SELECT COUNT(*) FROM dolt_conflicts_issues WHERE our_id = ?", key).Scan(&n)
if n == 0 { return nil } // nothing to resolve Try / catch
if err := ops.ResolveConflictRows(ctx, db, table, "theirs", keys); err != nil {
if strings.Contains(err.Error(), "was not cleared") {
return nil // already resolved by someone else; treat as success
}
return err
} Prevention
- Treat conflict resolution as idempotent and deduplicate concurrent resolvers.
- Refresh the conflict set right before each resolution batch.
- Don't replay resolution scripts without re-checking current conflict state.
When it happens
Trigger: Resolving a conflict row that was already deleted: another session resolved the same conflict concurrently, a whole-table strategy was applied elsewhere, or the key passed to ResolveConflictRows is stale (the conflict set changed since the key was read).
Common situations: Two operators or two automation runs resolving the same merge simultaneously; resolving keys obtained from an earlier listing after a rebase/merge changed state; replaying a resolution script twice.
Related errors
- their values for %s %s matched no row (was it deleted concur
- ErrStoreClosed
- %s of %s reported success but did not land (found assignee=%
- failed to get conflicts: %w
- failed to scan conflict: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/afcfdb6d7bff1c74.
Report an issue: GitHub.