gastownhall/beads · warning
no live conflict for %s %s
Error message
no live conflict for %s %s
What it means
loadConflictRow found no matching row in dolt_conflicts_<table> for the given key, so there is nothing to resolve at row level. This is thrown when the key no longer corresponds to a live conflict — usually because the conflict was already resolved (ours/theirs, or by the peer) between listing conflicts and resolving this one. It is a stale-list condition, not a data corruption.
Source
Thrown at internal/storage/versioncontrolops/conflicts.go:321
// either side's key column so a row only one side has is *found* and then
// refused with a precise message, rather than reported as "no conflict".
func loadConflictRow(ctx context.Context, db DBConn, table, keyCol, key string) (rawConflictRow, error) {
q := fmt.Sprintf("SELECT * FROM `dolt_conflicts_%s` WHERE `our_%s` = ? OR `their_%s` = ?", table, keyCol, keyCol) //nolint:gosec // identifiers validated
rows, err := db.QueryContext(ctx, q, key, key)
if err != nil {
return rawConflictRow{}, fmt.Errorf("query conflict for %s %s: %w", table, key, err)
}
defer func() { _ = rows.Close() }()
cols, err := rows.Columns()
if err != nil {
return rawConflictRow{}, fmt.Errorf("conflict columns for table %s: %w", table, err)
}
if !rows.Next() {
if err := rows.Err(); err != nil {
return rawConflictRow{}, fmt.Errorf("query conflict for %s %s: %w", table, key, err)
}
return rawConflictRow{}, fmt.Errorf("no live conflict for %s %s", table, key)
}
vals := make([]any, len(cols))
ptrs := make([]any, len(cols))
for i := range vals {
ptrs[i] = &vals[i]
}
if err := rows.Scan(ptrs...); err != nil {
return rawConflictRow{}, fmt.Errorf("scan conflict for %s %s: %w", table, key, err)
}
if rows.Next() {
return rawConflictRow{}, fmt.Errorf("multiple conflict rows for %s %s; resolve the whole table instead", table, key)
}
return rawConflictRow{cols: cols, vals: vals}, errors.Join(rows.Err(), rows.Close())
}
// conflictTargetStillPresent reports whether key still names a row of table.
//
// It is the matched-rows check the resolvers need after a write, becauseView on GitHub (pinned to 71377f2769)
Solutions
- Re-list the current conflicts (refresh the table view) and resolve only keys that still appear
- Check whether another session or process resolved the conflict concurrently
- If the merge was already committed or aborted, the conflict is gone — no action needed
- Retry the whole resolution pass atomically instead of replaying a stale key list
Example fix
// before
for _, key := range staleKeys {
resolveOne(ctx, db, table, keyCol, key, strategy) // fails: no live conflict
}
// after
keys, err := listConflictKeys(ctx, db, table) // re-read live conflict rows
for _, key := range keys {
resolveOne(ctx, db, table, keyCol, key, strategy)
} Defensive patterns
Strategy: validation
Validate before calling
// re-list live conflicts immediately before resolving each key
keys, err := listConflictKeys(ctx, db, table)
if err != nil { return err }
resolveSet := intersect(pendingKeys, keys) Try / catch
err := resolveOne(ctx, db, table, keyCol, key, strategy)
if err != nil && strings.Contains(err.Error(), "no live conflict for") {
// already resolved elsewhere; refresh list and continue
return refreshAndContinue()
}
return err Prevention
- Resolve conflicts from a freshly fetched list, never a cached one
- Run only one resolution session at a time per database
- Make resolution scripts idempotent: skip keys no longer in conflict
- Re-check merge state before and after batch resolution
When it happens
Trigger: ResolveConflictRows iterates a previously fetched conflict list and calls loadConflictRow for a key whose conflict row has already been deleted by an earlier resolution, a concurrent session, or because the merge was aborted/committed in the meantime.
Common situations: Running two `bd conflicts --theirs` sessions concurrently; resolving conflicts in a UI/CLI that cached the list; re-running a partially completed resolution script that already settled some rows.
Related errors
- query conflicts for table %s: %w
- query conflict for %s %s: %w
- multiple conflict rows for %s %s; resolve the whole table in
- conflict table dolt_conflicts_%s has no our_%s/their_%s colu
- conflict for %s %s is not a modify/modify conflict (one side
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/bf390f12c6b16432.
Report an issue: GitHub.