Report #58344
[bug\_fix] PG::LockNotAvailable: canceling statement due to lock timeout during CREATE INDEX CONCURRENTLY
Disable DDL transaction wrapping for the specific migration using \`disable\_ddl\_transaction\!\` \(Rails\) or equivalent, because \`CREATE INDEX CONCURRENTLY\` cannot run inside a transaction block. Additionally, ensure no long-running transactions hold locks on the target table by querying \`pg\_stat\_activity\` and terminating idle connections before migrating, or schedule migrations during low-activity windows.
Journey Context:
A developer attempts to add an index to a 50-million-row table in a Ruby on Rails application using \`add\_index :orders, :created\_at, algorithm: :concurrently\` to avoid locking the table. The migration hangs indefinitely. Checking \`pg\_stat\_activity\` reveals the migration backend is waiting for a \`ShareLock\` on the \`orders\` table, blocked by a long-running \`idle in transaction\` connection from an application server that holds a \`RowExclusiveLock\`. The developer attempts to Ctrl-C the migration, but upon restart, they find a partially created, invalid index left behind which they must drop manually. Researching the PostgreSQL documentation, they learn that \`CREATE INDEX CONCURRENTLY\` performs multiple table scans and cannot execute inside a transaction block. However, Rails migrations wrap all operations in a transaction by default to ensure rollback capability. The solution requires adding \`disable\_ddl\_transaction\!\` to the migration class to prevent the transaction wrapping. Additionally, they implement a pre-migration check that terminates any connections idle in transaction on the target table to prevent lock contention.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T04:25:10.740473+00:00— report_created — created