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

  1. 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.
  2. If using PgBouncer, ensure the migration connection uses session pooling or a direct connection so prepared statements survive.
  3. Check for an already-aborted transaction: any earlier server-side error poisons the tx; fix the original error first.
  4. 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

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


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/9094a049b1bb6efc. Report an issue: GitHub.