gastownhall/beads · error

query schema_migrations conflicts: %w

Error message

query schema_migrations conflicts: %w

What it means

This error comes from schemaMigrationsConflictsAreVintageOnly when the query against dolt_conflicts_schema_migrations fails. The function inspects every conflicted schema_migrations row to confirm all conflicts are 'vintage' (same version on both sides with equal or one-sided-empty content hashes) before the library auto-resolves them; if the query fails, the error is wrapped with 'query schema_migrations conflicts:' and auto-resolution is abandoned so the operator must resolve manually. Like its config counterpart, it is a wrapper over a driver-level failure.

Source

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

			keys = append(keys, key.String)
		}
	}
	return keys, rows.Err()
}

// schemaMigrationsConflictsAreVintageOnly reports whether every conflicted
// schema_migrations row is the same migration version present on BOTH sides
// whose content hashes are compatible: equal, or NULL/empty on exactly one side
// (a pre-#4270 binary recorded the version without a hash, bd-6dnrw.29). Two
// different non-empty hashes mean the clones applied different content for the
// same version — the #4259 schema fork — and are never auto-resolved. A row
// deleted on one side is not a vintage artifact either.
func schemaMigrationsConflictsAreVintageOnly(ctx context.Context, db DBConn) (bool, error) {
	rows, err := db.QueryContext(ctx, `
		SELECT our_version, their_version, our_content_hash, their_content_hash
		FROM dolt_conflicts_schema_migrations`)
	if err != nil {
		return false, fmt.Errorf("query schema_migrations conflicts: %w", err)
	}
	defer rows.Close()

	for rows.Next() {
		var ourVersion, theirVersion sql.NullInt64
		var ourHash, theirHash sql.NullString
		if err := rows.Scan(&ourVersion, &theirVersion, &ourHash, &theirHash); err != nil {
			return false, fmt.Errorf("scan schema_migrations conflict: %w", err)
		}
		if !ourVersion.Valid || !theirVersion.Valid || ourVersion.Int64 != theirVersion.Int64 {
			return false, nil
		}
		ours, theirs := ourHash.String, theirHash.String
		if ours != "" && theirs != "" && ours != theirs {
			return false, nil // real content skew (#4259) — operator decides
		}
	}
	return true, rows.Err()

View on GitHub (pinned to 71377f2769)

Solutions

  1. Confirm schema_migrations is actually in conflict (SHOW TABLES / dolt conflicts) — if the conflict table is absent on this Dolt version, upgrade Dolt or skip the pre-check.
  2. Retry the auto-resolve after verifying the Dolt database is reachable and no other process holds the database lock.
  3. Align bd and Dolt engine versions: a pre-#4270 binary's missing content_hash columns can make the conflict-table shape differ.
  4. If the query keeps failing, resolve schema_migrations conflicts manually (dolt conflicts resolve --ours schema_migrations) after verifying versions/hashes yourself.
  5. Check storage health with 'bd doctor' for embedded-mode issues.

Example fix

// before: unconditionally query the conflict table
rows, err := db.QueryContext(ctx, `
	SELECT our_version, their_version, our_content_hash, their_content_hash
	FROM dolt_conflicts_schema_migrations`)
if err != nil {
	return false, fmt.Errorf("query schema_migrations conflicts: %w", err)
}
// after: treat 'table not found' as no conflicts
rows, err := db.QueryContext(ctx, `
	SELECT our_version, their_version, our_content_hash, their_content_hash
	FROM dolt_conflicts_schema_migrations`)
if err != nil {
	if isNoSuchTableErr(err) {
		return true, nil
	}
	return false, fmt.Errorf("query schema_migrations conflicts: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Preflight: confirm schema_migrations is actually conflicted and the
// conflict table is queryable before attempting vintage auto-resolution.
var n int
if err := db.QueryRowContext(ctx,
    "SELECT COUNT(*) FROM dolt_conflicts_schema_migrations").Scan(&n); err != nil {
    return fmt.Errorf("schema_migrations conflict preflight failed: %w", err)
}

Try / catch

err := TryAutoResolveMergeConflicts(ctx, db)
if err != nil {
    if strings.Contains(err.Error(), "query schema_migrations conflicts") {
        // driver-level failure: reconnect or resolve manually with
        // dolt conflicts resolve --ours schema_migrations
    }
}

Prevention

When it happens

Trigger: TryAutoResolveMergeConflicts runs after a merge that conflicted on schema_migrations, and 'SELECT our_version, their_version, our_content_hash, their_content_hash FROM dolt_conflicts_schema_migrations' fails — the table doesn't exist (no such conflict class on this Dolt version or the table was already resolved), the connection/transaction is dead, or the driver returns an I/O/lock error.

Common situations: Dolt version drift: older binaries (pre-#4270) recorded schema_migrations without a content_hash column, so conflict tables on upgraded repos may mismatch expectations; repos where a previous resolve already cleared the conflict table; embedded Dolt connection failures or flocks held by another bd process; network loss against a remote Dolt server.

Related errors


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