{"record":{"id":"6d2e306626191b1e","repo":"gastownhall/beads","slug":"schema-migration-w","errorCode":null,"errorMessage":"schema migration: %w","messagePattern":"schema migration: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/storage/dolt/store.go","lineNumber":2610,"sourceCode":") (int, error) {\n\tconn, err := db.Conn(ctx)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"schema: pin connection: %w\", err)\n\t}\n\tdefer conn.Close()\n\n\tvar dbName string\n\tif err := conn.QueryRowContext(ctx, \"SELECT DATABASE()\").Scan(&dbName); err != nil {\n\t\treturn 0, fmt.Errorf(\"schema: read database name: %w\", err)\n\t}\n\n\tvar opts []schema.MigrateLockOption\n\tif bootstrapHeal != nil {\n\t\topts = append(opts, schema.WithFreshBootstrapHeal(bootstrapHeal, endpoint))\n\t}\n\tapplied, err := schema.MigrateUpWithLock(ctx, conn, dbName, opts...)\n\tif err != nil {\n\t\treturn applied, fmt.Errorf(\"schema migration: %w\", err)\n\t}\n\treturn applied, nil\n}\n\nfunc initSchemaOnDBWithRetry(ctx context.Context, db *sql.DB) (int, error) {\n\treturn initSchemaOnDBWithRetryAndGate(ctx, db, nil)\n}\n\n// initSchemaOnDBWithRetryAndGate is initSchemaOnDBWithRetry with an optional\n// pre-migration gate run INSIDE the retry loop. The gate's own reads\n// (schema_migrations, dolt_remotes) can hit the same transient Dolt\n// startup/catalog races the migration retry absorbs, so gate probe errors are\n// retried with them instead of failing the open fast (bd-6dnrw.30); a\n// *schema.RemoteMigrateGateError refusal stays permanent.\nfunc initSchemaOnDBWithRetryAndGate(ctx context.Context, db *sql.DB, gate func(context.Context, *sql.DB) error) (int, error) {\n\treturn initSchemaOnDBWithRetryAndGateBootstrapHeal(ctx, db, gate, nil, \"\")\n}\n","sourceCodeStart":2592,"sourceCodeEnd":2628,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/store.go#L2592-L2628","documentation":"This wraps any failure from schema.MigrateUpWithLock, which runs pending schema migrations on the pinned connection while holding a migration lock. The database may be left partially migrated ('dirty') if a migration itself failed midway, so this error should never be blindly retried without checking migration state.","triggerScenarios":"Calling schema init/migrate when: a migration SQL statement fails, the migration lock cannot be acquired (another process migrating), the schema_migrations table is inconsistent, or the connection drops mid-migration.","commonSituations":"Concurrent processes (two app instances) racing to migrate at startup, a previously failed migration left dirty state, Dolt server killed during migration, schema migration files referencing unsupported Dolt SQL features.","solutions":["Read the wrapped error to see which migration step failed; inspect the schema_migrations/table state before retrying","Ensure only one process runs migrations at a time (single-instance init or external lock/leader election)","Fix or roll back the failed migration, then re-run","Verify the Dolt SQL server supports every statement in the failing migration"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// check migration state before re-running\nvar dirty bool\nvar version int\nrow := conn.QueryRowContext(ctx,\n    \"SELECT version, dirty FROM schema_migrations LIMIT 1\")\nif err := row.Scan(&version, &dirty); err == nil && dirty {\n    // resolve dirty state manually before retrying migrations\n}","typeGuard":null,"tryCatchPattern":"// Go: never auto-retry blindly; detect dirty state\napplied, err := schema.MigrateUpWithLock(ctx, conn, dbName, opts...)\nif err != nil {\n    var lockErr *schema.LockError\n    if errors.As(err, &lockErr) {\n        // another migrator holds the lock: back off and retry\n    } else {\n        // migration itself failed: inspect schema_migrations, don't blind-retry\n    }\n    return err\n}","preventionTips":["Run migrations from a single process (leader election or init container)","Treat any migration failure as requiring manual state inspection","Keep migration steps idempotent and small","Test migrations against Dolt before production rollout"],"tags":["go","database","schema-migration","mysql"],"backgroundTag":"migration-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}