bytebase/bytebase · error
failed to prepare UI Plan draft backfill
Error message
failed to prepare UI Plan draft backfill
What it means
The batch prepares a parameterized INSERT statement that will create one draft OPEN issue per eligible Plan. This error wraps a failure of tx.PrepareContext — i.e. the server rejected the prepared statement, typically because of a SQL syntax/type problem or because the transaction/connection was already broken. Preparation happens once per batch before the loop that executes it.
Source
Thrown at backend/migrator/migration_3_21_1.go:234
FOR UPDATE`, projectID).Scan(&lockedProjectID); err != nil {
return errors.Wrapf(err, "failed to lock project %s", projectID)
}
var issueID int64
if err := tx.QueryRowContext(ctx, `
SELECT GREATEST(COALESCE(MAX(id), 0), 100)
FROM issue
WHERE project = $1`, projectID).Scan(&issueID); err != nil {
return errors.Wrapf(err, "failed to get maximum issue ID for project %s", projectID)
}
statement, err := tx.PrepareContext(ctx, `
INSERT INTO issue (
id, creator, created_at, updated_at, project, plan_id,
name, status, type, description, payload, ts_vector
) VALUES ($1, $2, $3, $3, $4, $5, $6, 'OPEN', 'DATABASE_CHANGE', $7, '{"draft":true}', $8)`)
if err != nil {
return errors.Wrap(err, "failed to prepare UI Plan draft backfill")
}
defer statement.Close()
for _, candidate := range eligible {
issueID++
if _, err := statement.ExecContext(
ctx,
issueID,
candidate.creator,
migrationTime,
candidate.projectID,
candidate.planID,
candidate.title,
candidate.description,
store.IssueSearchVector(candidate.title, candidate.description),
); err != nil {
return errors.Wrapf(err, "failed to backfill draft issue for Plan %s/%d", candidate.projectID, candidate.planID)
}View on GitHub (pinned to 1870550677)
Solutions
- Inspect the wrapped error: 'relation does not exist' or 'column does not exist' means schema drift — align the DB with LATEST.sql and complete any missing migrations.
- If using PgBouncer, ensure the migration connection uses session pooling or a direct connection so prepared statements survive.
- Check for an already-aborted transaction: any earlier server-side error poisons the tx; fix the original error first.
- Re-run the migration after restoring connectivity — it is idempotent per batch.
Example fix
// before: prepare fails over a pooled connection that lost session state
statement, err := tx.PrepareContext(ctx, `INSERT INTO issue (...) VALUES ($1, $2, $3, $3, $4, $5, $6, 'OPEN', 'DATABASE_CHANGE', $7, '{"draft":true}', $8)`)
// after: connect the migrator directly to Postgres (bypass PgBouncer) or use session pooling
// PG_URL=postgresql://bbdev@localhost:5432/bbdev?sslmode=disable (direct, not :6432 pgbouncer) Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: required columns exist
SELECT column_name FROM information_schema.columns
WHERE table_name = 'issue'
AND column_name IN ('id','creator','project','plan_id','name','ts_vector'); Try / catch
if err := migrate(ctx); err != nil {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && (pgErr.Code == "42703" || pgErr.Code == "42P01") {
return fmt.Errorf("schema drift detected (%s); complete pending migrations first", pgErr.Message)
}
return err
} Prevention
- Never skip migrations; upgrade one version at a time
- Bypass PgBouncer transaction pooling for migration connections
- Check for aborted transactions poisoning later statements
- Diff the live schema against LATEST.sql after restores
When it happens
Trigger: tx.PrepareContext fails because the connection underlying the transaction was dropped (previous lock waits, network hiccup); the issue table schema differs from what the statement expects (e.g. missing ts_vector or plan_id column after a partial migration history); the transaction was already aborted by an earlier server-side error.
Common situations: Metadata database schema drifted from the version line (skipped migrations, botched restore); connection idle timeouts killing long-running migration transactions; running against a Postgres version with quirks around prepared statements via PgBouncer in transaction-pooling mode.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- failed to commit empty UI Plan draft backfill batch
- failed to lock project %s
- failed to get maximum issue ID for project %s
- failed to commit UI Plan draft backfill batch
- failed to list UI Plan draft candidates
AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06).
Data as JSON: /api/errors/9094a049b1bb6efc.
Report an issue: GitHub.