gastownhall/beads · error

failed to scan conflict: %w

Error message

failed to scan conflict: %w

What it means

While iterating rows from dolt_conflicts, rows.Scan failed to decode a (table, num_conflicts) pair into the local struct — e.g. unexpected column types or NULL values. The function closes the rows and returns this wrapped error instead of continuing with partial data.

Source

Thrown at internal/storage/versioncontrolops/mergesettle.go:444

// The resolved tables are staged but NOT committed: the caller must run
// CommitResolvedConflicts after the FK cascade repair, because DOLT_COMMIT
// refuses a working set with outstanding constraint violations (bd-578h9.14).
func TryAutoResolveMergeConflicts(ctx context.Context, db DBConn) (bool, error) {
	rows, err := db.QueryContext(ctx, "SELECT `table`, num_conflicts FROM dolt_conflicts")
	if err != nil {
		return false, fmt.Errorf("failed to query conflicts: %w", err)
	}

	type conflict struct {
		table string
		count int
	}
	var conflicts []conflict
	for rows.Next() {
		var c conflict
		if err := rows.Scan(&c.table, &c.count); err != nil {
			_ = rows.Close()
			return false, fmt.Errorf("failed to scan conflict: %w", err)
		}
		conflicts = append(conflicts, c)
	}
	_ = rows.Close()
	if err := rows.Err(); err != nil {
		return false, err
	}

	if len(conflicts) == 0 {
		return false, nil // No conflicts to resolve — error was something else
	}

	// Decide which conflicted tables are safe to auto-resolve. If any conflict is
	// not safely resolvable, resolve nothing and let the pull fail.
	var resolvable []string
	var issuesPlan []issuesRowMerge
	var unionPlans map[string][]unionRowKey
	for _, c := range conflicts {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect raw rows: `SELECT \`table\`, num_conflicts FROM dolt_conflicts` and look for NULLs/odd types
  2. Upgrade or align the Dolt server version with what bd expects
  3. Clean the interrupted merge state (DOLT_MERGE_ABORT) so conflict metadata is rebuilt on next merge
  4. Scan into sql.NullString/sql.NullInt64 to tolerate NULLs in custom forks

Example fix

// before
rows.Scan(&c.table, &c.count) // fails on NULL
// after
var t sql.NullString; var n sql.NullInt64
rows.Scan(&t, &n)
c.table, c.count = t.String, int(n.Int64)
Defensive patterns

Strategy: type-guard

Validate before calling

rows, _ := db.QueryContext(ctx, "SELECT \"table\", num_conflicts FROM dolt_conflicts")
// verify all rows non-NULL before relying on auto-resolve

Type guard

func validConflictRow(table string, count int) bool {
    return table != "" && count >= 0
}

Try / catch

ok, err := TryAutoResolveMergeConflicts(ctx, db)
if err != nil && strings.Contains(err.Error(), "scan conflict") {
    // Dolt version mismatch on dolt_conflicts schema — abort merge and upgrade
    _ = db.ExecContext(ctx, "CALL DOLT_MERGE_ABORT()")
}

Prevention

When it happens

Trigger: A row in dolt_conflicts has NULL `table` or a num_conflicts value that cannot scan into int (type mismatch across Dolt versions).

Common situations: Dolt server version where dolt_conflicts columns differ in type/name; corrupted conflict metadata after an interrupted merge.

Related errors


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