Report #67572
[bug\_fix] current transaction is aborted, commands ignored until end of transaction block \(SQLSTATE 25P02\) following an earlier error
Ensure that application exception handlers always issue a ROLLBACK \(or ROLLBACK TO SAVEPOINT\) when catching any exception inside a transaction block before attempting new queries. Use context managers \(e.g., Python's contextlib, Java's try-with-resources, or Go's defer\) that guarantee cleanup. Alternatively, set the connection to autocommit mode for ad-hoc queries that don't need explicit transactions, ensuring each statement is its own implicit transaction.
Journey Context:
A developer writes a Python Flask endpoint that performs two updates in a single transaction: update account balance, then insert audit log. They wrap it in a try-except block. The first UPDATE fails due to a check constraint violation \(e.g., negative balance\). PostgreSQL marks the transaction as aborted \(state = idle in transaction \(aborted\)\). The exception handler catches the IntegrityError, logs it, and then tries to execute a SELECT to check the account status before returning a 400 error. This SELECT is sent on the same connection. PostgreSQL returns "ERROR: current transaction is aborted, commands ignored until end of transaction block" \(25P02\). The developer sees this secondary error in logs and is confused because the original constraint violation is lost in the noise. They realize that once any error occurs in a PostgreSQL transaction, the transaction is poisoned and must be rolled back before any new commands are accepted. They fix the exception handler to execute conn.rollback\(\) immediately upon catching any database error, or use a context manager that ensures rollback on exit. The secondary errors disappear and the original constraint violation is properly logged.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T19:54:14.358289+00:00— report_created — created