gastownhall/beads · warning

uow: switching to database: %w

Error message

uow: switching to database: %w

What it means

On the team-server open path, verifyTeamServerSchema runs USE <database> via the DDL repository. If it fails with a serialization error, the error is wrapped as 'uow: switching to database: %w' and returned bare so initSchema's backoff retries. Otherwise the failure is terminal.

Source

Thrown at internal/storage/uow/dolt_sql_provider.go:248

	}
	if _, err := schema.MigrateUpWithLock(ctx, conn, database,
		schema.WithDatabaseSelector(selectProbeDatabase),
		schema.WithLockedPreparation(p.serverEndpoint, preparer.prepare)); err != nil {
		return classifyInitSchemaError(err)
	}
	return nil
}

// verifyTeamServerSchema is the team-server open path: the schema is owned by
// beads-team-server (bts), so bd never creates the database or migrates. It
// attaches to the existing database and verifies the schema version, then the
// project identity — identity is checked only after the schema check proves the
// metadata table exists at this binary's version.
func (p *doltSQLProvider) verifyTeamServerSchema(ctx context.Context, conn *sql.Conn, database string) error {
	ddl := db.NewDDLSQLRepository(conn)
	if err := ddl.UseDatabase(ctx, database); err != nil {
		if isSerializationError(err) {
			return fmt.Errorf("uow: switching to database: %w", err)
		}
		return backoff.Permanent(fmt.Errorf(
			"uow: database %q not found — the schema is managed by beads-team-server; ask your operator to run 'bts init' first: %w",
			database, err))
	}
	if err := checkTeamServerSchema(ctx, conn, database); err != nil {
		if isSerializationError(err) {
			return fmt.Errorf("uow: team-server schema check: %w", err)
		}
		return backoff.Permanent(err)
	}
	if err := checkTeamServerIdentity(ctx, conn, database, p.expectedProjectID); err != nil {
		if isSerializationError(err) {
			return fmt.Errorf("uow: team-server identity check: %w", err)
		}
		return backoff.Permanent(err)
	}
	return nil

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry — the backoff loop will re-attempt the USE once the peer's work settles.
  2. Coordinate with the operator: ensure 'bts init' completed before clients connect.
  3. Check server load; serialization errors spike on heavily contended Dolt servers.
  4. If persistent, inspect the wrapped cause for the specific conflicting statement.
Defensive patterns

Strategy: retry

Validate before calling

// check the team server is up and the database exists before connecting clients
rows, err := adminConn.QueryContext(ctx, "SHOW DATABASES LIKE ?", dbName)
if err != nil { return err }
if !rows.Next() {
    return fmt.Errorf("database %q missing on team server — run 'bts init' first", dbName)
}

Type guard

if uow.IsSerializationError(err) { /* transient USE failure — retryable */ }

Try / catch

err := provider.Open(ctx, cfg)
if err != nil {
    if uow.IsSerializationError(err) {
        // team server busy — retry with backoff
        return backoff.Retry(openFn, bo)
    }
    return err
}

Prevention

When it happens

Trigger: initSchemaAttempt (teamServer=true) calls verifyTeamServerSchema; ddl.UseDatabase fails with a serialization-class error on the shared beads-team-server, typically while another session is migrating or committing on the server.

Common situations: Operator running 'bts init' concurrently with the first bd clients connecting; Dolt serialization conflicts on a loaded shared team server during startup.

Related errors


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