gastownhall/beads · error · bootstrapPreparationError

uow: creating database: %w

Error message

uow: creating database: %w

What it means

This error is produced by bootstrapPreparer.prepare when the sticky re-assert path (b.created already true from a prior attempt) calls CreateDatabaseIfNotExists and the CREATE IF NOT EXISTS fails for a non-serialization reason. It is wrapped in a bootstrapPreparationError without retryable=true, so it is terminal for the initSchema backoff loop. This path exists so a database dropped between attempts (e.g. concurrent clean-databases) is recreated rather than failing the subsequent USE.

Source

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

	// never inferred again from probing or CREATE IF NOT EXISTS.
	created bool
	// heal is the one-shot capability captured in the CREATE-winning attempt and
	// re-returned unchanged on later attempts.
	heal *schema.FreshBootstrapHealCapability
}

// prepare is MigrateUpWithLock's locked-preparation callback. It (re)creates and
// selects the target database and, only in the attempt that won the bare CREATE,
// captures the fresh-bootstrap heal capability. See bootstrapPreparer.
func (b *bootstrapPreparer) prepare(ctx context.Context, conn *sql.Conn) (*schema.FreshBootstrapHealCapability, error) {
	ddl := db.NewDDLSQLRepository(conn)
	justCreated := false
	if b.created {
		// Re-assert on retries so a database dropped between attempts
		// (e.g. a concurrent clean-databases) is recreated rather than
		// failing the USE below.
		if err := ddl.CreateDatabaseIfNotExists(ctx, b.database); err != nil {
			return nil, &bootstrapPreparationError{err: fmt.Errorf("uow: creating database: %w", err)}
		}
	} else {
		switch err := ddl.CreateDatabase(ctx, b.database); {
		case err == nil:
			b.created = true
			justCreated = true
		case isDatabaseExistsError(err):
			// Pre-existing (or a concurrent initializer won the create
			// race): not ours, heal stays off.
		case isSerializationError(err):
			// Only the initial bare CREATE preserves its historical
			// serialization retry classification. The later sticky CREATE,
			// USE, and identity capture remain permanent regardless of
			// their nested driver error.
			return nil, &bootstrapPreparationError{
				err:       fmt.Errorf("uow: creating database: %w", err),
				retryable: true,
			}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped driver error for the root cause and fix it — commonly granting the connecting user CREATE privilege on the server.
  2. Verify the configured database name is valid and that the server endpoint accepts DDL (not a read-only replica).
  3. Stop any concurrent clean-databases / dropping job racing with bd init, then re-run the command.
  4. Check connectivity to the Dolt server and re-run init.

Example fix

// before (insufficient privilege)
CREATE DATABASE IF NOT EXISTS beads_ws; -- ERROR 1044: access denied

// after (as server admin)
GRANT CREATE, ALTER ON `beads_ws`.* TO 'beads'@'%';
FLUSH PRIVILEGES;
Defensive patterns

Strategy: validation

Validate before calling

// Verify the connecting user can create databases BEFORE running init:
var unused string
if err := conn.QueryRowContext(ctx, "SELECT 1").Err(); err != nil { return err }
// Probe DDL privilege on the server (server-appropriate check) or confirm grants:
// SHOW GRANTS FOR CURRENT_USER; must include CREATE privilege.
if err := checkCreatePrivilege(ctx, conn); err != nil {
	return fmt.Errorf("bootstrap requires CREATE privilege: %w", err)
}

Type guard

func isPermanentPreparation(err error) bool {
	var bpe *bootstrapPreparationError
	return errors.As(err, &bpe) && !bpe.retryable
}

Try / catch

if err := bdInit(ctx); err != nil {
	var bpe *bootstrapPreparationError
	if errors.As(err, &bpe) && !bpe.retryable {
		log.Fatalf("terminal database creation failure: %v — check grants/DDL permissions", bpe.err)
	}
	return err // retryable path handled by backoff
}

Prevention

When it happens

Trigger: A retry attempt of initSchema whose CREATE already succeeded earlier (b.created sticky), but the re-assert CREATE DATABASE IF NOT EXISTS fails — e.g. permission denied for CREATE, invalid database name/charset, server refusing DDL, or connection dropped mid-DDL with a non-serialization error.

Common situations: Database credentials lacking CREATE privilege after an ACL change; server-side DDL restrictions or read-only replica; database name violating server naming rules; concurrent process actively dropping databases while init retries; network interruption to a remote Dolt server.

Related errors


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