{"record":{"id":"87092216ea33a5ae","repo":"bytebase/bytebase","slug":"failed-to-commit-empty-ui-plan-draft-backfill-batc","errorCode":null,"errorMessage":"failed to commit empty UI Plan draft backfill batch","messagePattern":"failed to commit empty UI Plan draft backfill batch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/migrator/migration_3_21_1.go","lineNumber":206,"sourceCode":"\t\tkey := candidate.projectID + \"/\" + strconv.FormatInt(candidate.planID, 10)\n\t\tif err := store.AcquireAdvisoryXactLockWithStringKey(\n\t\t\tctx,\n\t\t\ttx,\n\t\t\tstore.AdvisoryLockKeyPlanIssueRollout,\n\t\t\tkey,\n\t\t); err != nil {\n\t\t\treturn errors.Wrapf(err, \"failed to lock Plan %s\", key)\n\t\t}\n\t\tplanIDs = append(planIDs, candidate.planID)\n\t}\n\n\teligible, err := findMigration3_21_1Candidates(ctx, tx, migrationTime, projectID, planIDs, nil, nil, 0, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(eligible) == 0 {\n\t\tif err := tx.Commit(); err != nil {\n\t\t\treturn errors.Wrap(err, \"failed to commit empty UI Plan draft backfill batch\")\n\t\t}\n\t\treturn nil\n\t}\n\n\tvar lockedProjectID string\n\tif err := tx.QueryRowContext(ctx, `\n\t\tSELECT resource_id\n\t\tFROM project\n\t\tWHERE resource_id = $1\n\t\tFOR UPDATE`, projectID).Scan(&lockedProjectID); err != nil {\n\t\treturn errors.Wrapf(err, \"failed to lock project %s\", projectID)\n\t}\n\n\tvar issueID int64\n\tif err := tx.QueryRowContext(ctx, `\n\t\tSELECT GREATEST(COALESCE(MAX(id), 0), 100)\n\t\tFROM issue\n\t\tWHERE project = $1`, projectID).Scan(&issueID); err != nil {","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/migrator/migration_3_21_1.go#L188-L224","documentation":"This error wraps a database transaction Commit failure that occurs when migrate3_21_1Batch finds zero eligible UI Plan draft candidates in the current batch and commits the (empty) transaction, releasing the plan row locks acquired earlier. The migration itself is fine; the wrapped cause is the underlying Postgres error from COMMIT. It is only thrown when the advisory-locked rows turned out to be already handled or filtered out by the re-check query.","triggerScenarios":"Calling migrate3_21_1Batch with candidate rows whose per-plan advisory locks were acquired, but findMigration3_21_1Candidates returns zero eligible rows (e.g. another worker already inserted the draft issue between the initial listing and this batch), and then database.Tx.Commit fails due to connection drop, serialization/conflict, statement timeout, or the server shutting down mid-migration.","commonSituations":"Running the 3.21.1 upgrade against a production Postgres that drops connections or hits a lock conflict with a concurrently running Bytebase instance; terminating the migration midway (context cancellation); network partition between the migrator and the metadata database during a large upgrade.","solutions":["Check the wrapped cause (err.Cause() / logs) for the actual Postgres COMMIT error and fix it (network, timeout, connection pool settings).","Re-run the migration: the batch transaction rolled back atomically, so it is safe to retry the 3.21.1 migration.","Ensure only one Bytebase instance runs migrations at once; the advisory locks only serialize plan-level, not instance-level, work (see withMigrationGuard).","Verify metadata DB health (pg_stat_activity for blocking sessions, statement_timeout) before retrying."],"exampleFix":"// before: batch commit fails silently amid connection churn\nif err := tx.Commit(); err != nil {\n\treturn errors.Wrap(err, \"failed to commit empty UI Plan draft backfill batch\")\n}\n// after: fail fast on a cancelled/deadline-exceeded context before committing\nif err := ctx.Err(); err != nil {\n\treturn errors.Wrap(err, \"migration context cancelled before commit\")\n}\nif err := tx.Commit(); err != nil {\n\treturn errors.Wrap(err, \"failed to commit empty UI Plan draft backfill batch\")\n}","handlingStrategy":"retry","validationCode":"// before upgrading: ensure only one instance migrates and the DB is reachable\nif err := db.PingContext(ctx); err != nil { return err }\n// SELECT pg_try_advisory_lock(...) to check no other migrator is active","typeGuard":null,"tryCatchPattern":"err := runMigration(ctx)\nvar pgErr *pgconn.PgError\nif errors.As(err, &pgErr) {\n\tlog.Printf(\"commit failed: %s (code %s), safe to retry\", pgErr.Message, pgErr.Code)\n\treturn runMigration(ctx) // batch tx rolled back; retry is safe\n}\nreturn err","preventionTips":["Run schema migrations from a single instance only","Check DB connectivity and statement_timeout before starting upgrades","Retry failed migrations — batch transactions are atomic","Monitor pg_stat_activity for blocking sessions during upgrades"],"tags":["database","migration","transaction","postgres"],"backgroundTag":"database-write-failed","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}