25P02 — in_failed_sql_transaction
25P02 — in_failed_sql_transaction
At a glance
25P02 is usually the second diagnostic, not the root cause. In the selected case a duplicate key first returns 23505; a following SELECT is rejected with 25P02 while the block remains INERROR. ROLLBACK is required before a valid retry.
| Field | Value |
|---|---|
| SQLSTATE | 25P02 |
| Condition | in_failed_sql_transaction |
| Status | active |
| Known present by | 7.4 |
| Locked snapshots | 9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3 |
| Macros | ERRCODE_IN_FAILED_SQL_TRANSACTION |
| Aliases | — |
Meaning
postgres.c checks the aborted transaction state before planning another ordinary command and reports current transaction is aborted, commands ignored until end of transaction block. A driver exposes the corresponding failed transaction status; the original error remains the diagnostic anchor, while 25P02 tells the client that ordinary work is no longer admissible in this block.
Diagnosis
Locate the first statement error before acting on 25P02, and log both diagnostics with the connection transaction status. The selected runs show root 23505, then 25P02, INERROR after each, IDLE after ROLLBACK, and a committed valid row after a new explicit BEGIN/COMMIT. Check whether a savepoint was established before the root error: ROLLBACK TO SAVEPOINT can preserve the outer transaction, whereas without one the whole failed block must end. A pool must not hand an INERROR connection to another request.
Response
Stop issuing business statements after the first error. Preserve the root SQLSTATE and details. If a deliberately established savepoint is still usable, roll back to it and continue the outer transaction; otherwise issue ROLLBACK, verify the connection is IDLE, and start a fresh transaction. Re-evaluate the operation instead of blindly replaying the root statement.
Source message
The fixed primary message is current transaction is aborted, commands ignored until end of transaction block. It describes the state left by an earlier error and does not replace the root SQLSTATE, DETAIL, or constraint identity.
Observed diagnostics
18.6 (Homebrew) / latest: root SQLSTATE 23505; secondary SQLSTATE 25P02; after root/secondary INERROR; after rollback IDLE; rows [[1, 'seed'], [2, 'repaired']].
10.21 (Debian 10.21-1.pgdg90+1) / pg10: root SQLSTATE 23505; secondary SQLSTATE 25P02; after root/secondary INERROR; after rollback IDLE; rows [[1, 'seed'], [2, 'repaired']].
Representative case
The runner reads the root error, secondary diagnostic, rollback, and valid retry statements below from the shared registry; complete assertions, environment, and cleanup are in case export.
The SQLSTATE, diagnostics, states, and repair assertions for this excerpt come from the shared registry (SHA-256 04da3240dcf3c03fe60d13715f8187350fadf5b8d1f10e5b837acd45289759cd); structured evidence.
Authored evidence IDs: identity, abort-state, runtime. Selected runtime records: runtime.25P02-batch2-latest-20260909.latest, runtime.25P02-batch2-pg10-20260909.pg10.
Versions and limits
The selected duplicate-key-to-25P02 case passes on PostgreSQL 18.6 and 10.21. It demonstrates transaction-state recovery, not a claim that the duplicate itself can be retried unchanged.
Related
23505 unique violation, 25P01 no active SQL transaction, 40001 serialization failure.
Sources
src.errcodes.18.6(SHA-2566e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)src.calls.REL_18_6—raw/calls/REL_18_6.jsonl(SHA-2569ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)src.postgres.18.6(SHA-2569fb62275b1badf94d01ab351337b60410cd9b3ab1fe63fa9f23d6d2185a21061)doc.libpq.18.6(SHA-256a91ce8f29dde162245d2f35f839e8b7192f62a57e01020b80564af65edd09440) · official documentation