{"record":{"id":"9094a049b1bb6efc","repo":"bytebase/bytebase","slug":"failed-to-prepare-ui-plan-draft-backfill","errorCode":null,"errorMessage":"failed to prepare UI Plan draft backfill","messagePattern":"failed to prepare UI Plan draft backfill","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/migrator/migration_3_21_1.go","lineNumber":234,"sourceCode":"\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 {\n\t\treturn errors.Wrapf(err, \"failed to get maximum issue ID for project %s\", projectID)\n\t}\n\n\tstatement, err := tx.PrepareContext(ctx, `\n\t\tINSERT INTO issue (\n\t\t\tid, creator, created_at, updated_at, project, plan_id,\n\t\t\tname, status, type, description, payload, ts_vector\n\t\t) VALUES ($1, $2, $3, $3, $4, $5, $6, 'OPEN', 'DATABASE_CHANGE', $7, '{\"draft\":true}', $8)`)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"failed to prepare UI Plan draft backfill\")\n\t}\n\tdefer statement.Close()\n\n\tfor _, candidate := range eligible {\n\t\tissueID++\n\t\tif _, err := statement.ExecContext(\n\t\t\tctx,\n\t\t\tissueID,\n\t\t\tcandidate.creator,\n\t\t\tmigrationTime,\n\t\t\tcandidate.projectID,\n\t\t\tcandidate.planID,\n\t\t\tcandidate.title,\n\t\t\tcandidate.description,\n\t\t\tstore.IssueSearchVector(candidate.title, candidate.description),\n\t\t); err != nil {\n\t\t\treturn errors.Wrapf(err, \"failed to backfill draft issue for Plan %s/%d\", candidate.projectID, candidate.planID)\n\t\t}","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/migrator/migration_3_21_1.go#L216-L252","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: prepare fails over a pooled connection that lost session state\nstatement, err := tx.PrepareContext(ctx, `INSERT INTO issue (...) VALUES ($1, $2, $3, $3, $4, $5, $6, 'OPEN', 'DATABASE_CHANGE', $7, '{\"draft\":true}', $8)`)\n// after: connect the migrator directly to Postgres (bypass PgBouncer) or use session pooling\n// PG_URL=postgresql://bbdev@localhost:5432/bbdev?sslmode=disable  (direct, not :6432 pgbouncer)","handlingStrategy":"validation","validationCode":"// pre-flight: required columns exist\nSELECT column_name FROM information_schema.columns\nWHERE table_name = 'issue'\n  AND column_name IN ('id','creator','project','plan_id','name','ts_vector');","typeGuard":null,"tryCatchPattern":"if err := migrate(ctx); err != nil {\n\tvar pgErr *pgconn.PgError\n\tif errors.As(err, &pgErr) && (pgErr.Code == \"42703\" || pgErr.Code == \"42P01\") {\n\t\treturn fmt.Errorf(\"schema drift detected (%s); complete pending migrations first\", pgErr.Message)\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["database","migration","prepared-statement","postgres"],"backgroundTag":"sql-query-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"}