gastownhall/beads · error

scan constraint violation: %w

Error message

scan constraint violation: %w

What it means

While iterating dolt_constraint_violations, a row could not be scanned into storage.ConstraintViolation{Table, Count} — the table or num_violations value was NULL or of an incompatible type. This signals schema/version drift in the system table or corrupted violation records rather than normal operation.

Source

Thrown at internal/storage/versioncontrolops/conflicts.go:532

// constraintViolationCounts lists the tables carrying outstanding constraint
// violations. mergesettle.go repairs the FK-cascade class on the auto path;
// anything it declined lands here, blocking the commit.
func constraintViolationCounts(ctx context.Context, db DBConn) ([]storage.ConstraintViolation, error) {
	rows, err := db.QueryContext(ctx,
		"SELECT `table`, num_violations FROM dolt_constraint_violations WHERE num_violations > 0")
	if err != nil {
		if isMissingSystemTable(err) {
			return nil, nil
		}
		return nil, fmt.Errorf("query constraint violations: %w", err)
	}
	defer func() { _ = rows.Close() }()
	var out []storage.ConstraintViolation
	for rows.Next() {
		var v storage.ConstraintViolation
		if err := rows.Scan(&v.Table, &v.Count); err != nil {
			return nil, fmt.Errorf("scan constraint violation: %w", err)
		}
		out = append(out, v)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate constraint violations: %w", err)
	}
	return out, nil
}

// isMissingSystemTable reports whether err is dolt/MySQL's "table does not
// exist". Matched on the message because the embedded engine and the MySQL
// driver report it as different error types.
func isMissingSystemTable(err error) bool {
	if err == nil {
		return false
	}
	msg := strings.ToLower(err.Error())
	return strings.Contains(msg, "table not found") ||

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the table manually (SELECT *) to locate the malformed row and repair or clear it by resolving the underlying FK violation.
  2. Verify dolt engine version compatibility with bd; upgrade so column types match what the scan expects.
  3. Abort and redo the merge if the violations state is inconsistent, letting dolt rewrite the table.
  4. Resolve the specific table's constraint violations directly so its row disappears from the list.

Example fix

// before: strict scan into typed fields
var v storage.ConstraintViolation
if err := rows.Scan(&v.Table, &v.Count); err != nil { ... }
// after: tolerant scan with null checks
var table sql.NullString
var count sql.NullInt64
if err := rows.Scan(&table, &count); err != nil { ... }
if !table.Valid || !count.Valid { continue } // skip malformed row
Defensive patterns

Strategy: type-guard

Validate before calling

// Detect malformed violation rows before full resolution:
rows, _ := db.QueryContext(ctx, "SELECT `table`, num_violations FROM dolt_constraint_violations")
for rows.Next() {
  var t sql.NullString; var c sql.NullInt64
  if rows.Scan(&t, &c) != nil || !t.Valid || !c.Valid { /* corrupt row */ }
}

Type guard

func validViolationRow(t sql.NullString, c sql.NullInt64) bool { return t.Valid && c.Valid && c.Int64 > 0 }

Try / catch

if err != nil && strings.Contains(err.Error(), "scan constraint violation") {
  log.Printf("malformed dolt_constraint_violations row: %v — inspect manually", err)
}

Prevention

When it happens

Trigger: GetMergeBlockers iterating dolt_constraint_violations rows where table is NULL or num_violations is not integer-compatible — after engine upgrades, metadata corruption, or when the serving engine returns different column types than bd expects.

Common situations: Mixed dolt versions writing/reading the violations table; manual manipulation of dolt system tables; replicas or snapshots with partially written violation metadata.

Related errors


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