{"record":{"id":"e7309063438b50d3","repo":"gastownhall/beads","slug":"uow-creating-database-w","errorCode":null,"errorMessage":"uow: creating database: %w","messagePattern":"uow: creating database: %w","errorType":"exception","errorClass":"bootstrapPreparationError","httpStatus":null,"severity":"error","filePath":"internal/storage/uow/dolt_sql_provider.go","lineNumber":327,"sourceCode":"\t// never inferred again from probing or CREATE IF NOT EXISTS.\n\tcreated bool\n\t// heal is the one-shot capability captured in the CREATE-winning attempt and\n\t// re-returned unchanged on later attempts.\n\theal *schema.FreshBootstrapHealCapability\n}\n\n// prepare is MigrateUpWithLock's locked-preparation callback. It (re)creates and\n// selects the target database and, only in the attempt that won the bare CREATE,\n// captures the fresh-bootstrap heal capability. See bootstrapPreparer.\nfunc (b *bootstrapPreparer) prepare(ctx context.Context, conn *sql.Conn) (*schema.FreshBootstrapHealCapability, error) {\n\tddl := db.NewDDLSQLRepository(conn)\n\tjustCreated := false\n\tif b.created {\n\t\t// Re-assert on retries so a database dropped between attempts\n\t\t// (e.g. a concurrent clean-databases) is recreated rather than\n\t\t// failing the USE below.\n\t\tif err := ddl.CreateDatabaseIfNotExists(ctx, b.database); err != nil {\n\t\t\treturn nil, &bootstrapPreparationError{err: fmt.Errorf(\"uow: creating database: %w\", err)}\n\t\t}\n\t} else {\n\t\tswitch err := ddl.CreateDatabase(ctx, b.database); {\n\t\tcase err == nil:\n\t\t\tb.created = true\n\t\t\tjustCreated = true\n\t\tcase isDatabaseExistsError(err):\n\t\t\t// Pre-existing (or a concurrent initializer won the create\n\t\t\t// race): not ours, heal stays off.\n\t\tcase isSerializationError(err):\n\t\t\t// Only the initial bare CREATE preserves its historical\n\t\t\t// serialization retry classification. The later sticky CREATE,\n\t\t\t// USE, and identity capture remain permanent regardless of\n\t\t\t// their nested driver error.\n\t\t\treturn nil, &bootstrapPreparationError{\n\t\t\t\terr:       fmt.Errorf(\"uow: creating database: %w\", err),\n\t\t\t\tretryable: true,\n\t\t\t}","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/uow/dolt_sql_provider.go#L309-L345","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the wrapped driver error for the root cause and fix it — commonly granting the connecting user CREATE privilege on the server.","Verify the configured database name is valid and that the server endpoint accepts DDL (not a read-only replica).","Stop any concurrent clean-databases / dropping job racing with bd init, then re-run the command.","Check connectivity to the Dolt server and re-run init."],"exampleFix":"// before (insufficient privilege)\nCREATE DATABASE IF NOT EXISTS beads_ws; -- ERROR 1044: access denied\n\n// after (as server admin)\nGRANT CREATE, ALTER ON `beads_ws`.* TO 'beads'@'%';\nFLUSH PRIVILEGES;","handlingStrategy":"validation","validationCode":"// Verify the connecting user can create databases BEFORE running init:\nvar unused string\nif err := conn.QueryRowContext(ctx, \"SELECT 1\").Err(); err != nil { return err }\n// Probe DDL privilege on the server (server-appropriate check) or confirm grants:\n// SHOW GRANTS FOR CURRENT_USER; must include CREATE privilege.\nif err := checkCreatePrivilege(ctx, conn); err != nil {\n\treturn fmt.Errorf(\"bootstrap requires CREATE privilege: %w\", err)\n}","typeGuard":"func isPermanentPreparation(err error) bool {\n\tvar bpe *bootstrapPreparationError\n\treturn errors.As(err, &bpe) && !bpe.retryable\n}","tryCatchPattern":"if err := bdInit(ctx); err != nil {\n\tvar bpe *bootstrapPreparationError\n\tif errors.As(err, &bpe) && !bpe.retryable {\n\t\tlog.Fatalf(\"terminal database creation failure: %v — check grants/DDL permissions\", bpe.err)\n\t}\n\treturn err // retryable path handled by backoff\n}","preventionTips":["Grant the bd user CREATE (and ALTER) privileges on the target database before first init.","Validate the database name against server naming rules in configuration.","Ensure the Dolt server endpoint accepts DDL (not a read-only replica or restricted proxy).","Avoid scheduling clean-databases jobs that drop databases while clients are bootstrapping.","Test connectivity to the Dolt server before running init in CI."],"tags":["dolt","create-database","bootstrap","permissions","unit-of-work"],"backgroundTag":"database-create-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}