gastownhall/beads · error

clear %s conflict: %w

Error message

clear %s conflict: %w

What it means

The DELETE issued against dolt_conflicts_<table> failed at the database level; the underlying driver error is wrapped with this message. This means SQL execution itself failed — connection loss, lock contention, a missing or renamed conflict table, or a schema mismatch — not that zero rows matched.

Source

Thrown at internal/storage/versioncontrolops/automerge.go:716

	if _, ok := unionConflictKeyColumns[table]; !ok {
		return fmt.Errorf("table %s is not union-mergeable", table)
	}
	for _, row := range plan {
		preds := make([]string, 0, len(row.columns))
		args := make([]any, 0, len(row.columns))
		for i, k := range row.columns {
			v := row.values[i]
			if v == nil {
				return fmt.Errorf("unexpected %s conflict row with no our_%s (safety check bypassed)", table, k)
			}
			preds = append(preds, "`our_"+k+"` = ?")
			args = append(args, v)
		}
		//nolint:gosec // table and key columns come from the unionConflictKeyColumns allowlist.
		stmt := "DELETE FROM `dolt_conflicts_" + table + "` WHERE " + strings.Join(preds, " AND ")
		res, err := db.ExecContext(ctx, stmt, args...)
		if err != nil {
			return fmt.Errorf("clear %s conflict: %w", table, err)
		}
		if n, err := res.RowsAffected(); err == nil && n == 0 {
			return fmt.Errorf("a %s conflict was not cleared (no conflict row deleted)", table)
		}
	}
	return nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped %w cause to identify the SQL error (table missing vs connection vs lock timeout).
  2. If the conflict table no longer exists, the conflicts were likely already resolved — re-check conflict state before retrying.
  3. For transient connection/lock errors, retry the whole auto-resolve (re-running the check pass first) rather than resuming mid-plan.
  4. Ensure only one process at a time performs merge resolution on the repo to avoid concurrent clears.

Example fix

// before — treating every ExecContext failure as fatal without inspecting the cause
 if err != nil { return fmt.Errorf("clear %s conflict: %w", table, err) }
// after — retry transient errors once with a fresh check pass
 if err != nil {
     if errors.Is(err, driver.ErrBadConn) {
         return retryAutoResolve(ctx, db, table) // re-runs unionConflictsAreSafe then resolve
     }
     return fmt.Errorf("clear %s conflict: %w", table, err)
 }
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm the conflict table exists before resolving
var n int
if err := db.QueryRowContext(ctx,
	"SELECT COUNT(*) FROM information_schema.tables WHERE table_name = ?",
	"dolt_conflicts_"+table).Scan(&n); err == nil && n == 0 {
	return nil // nothing to resolve
}

Try / catch

err := resolveUnionConflicts(ctx, db, table, plan)
if err != nil {
	var driverErr *mysqldriver.MySQLError
	if errors.As(err, &driverErr) && isTransient(driverErr.Number) {
		// rebuild plan and retry once
	} else if strings.Contains(err.Error(), "doesn't exist") {
		// conflicts already cleared; treat as resolved
	} else {
		return err
	}
}

Prevention

When it happens

Trigger: db.ExecContext returns an error while running DELETE FROM `dolt_conflicts_<table>` WHERE our_<keycol> = ? — e.g. the database connection dropped mid-resolution, the conflict table doesn't exist (conflicts already cleared or never created), or a lock/timeout on the table.

Common situations: Another process resolved or cleared conflicts concurrently and dropped the conflict table; the dolt server restarted or the connection pool timed out during a long merge; Dolt returned a lock-wait timeout under concurrent write load.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/ba32cce38eb07e21. Report an issue: GitHub.