↑↓ select↵ open⌫ change scopeOpen full search

PG.CENTER connects PostgreSQL documentation, reference, and ecosystem knowledge. Maintained by Pigsty.

Wiki / SQLSTATE

25P02 — in_failed_sql_transaction

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.

English manual coverage begins with PostgreSQL 8.1. Source history and runtime observations have their own recorded version boundaries.

Reading PG 18·Select a recorded version

aliases
Unknown
class name
Invalid Transaction State
condition name
in_failed_sql_transaction
lang
en
sqlstate
25P02

Definition PG 18

25P02 — in_failed_sql_transaction

At a glance {#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.

Meaning {#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 {#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 {#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 {#messages}

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 {#observed}

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 {#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.

-- create
CREATE TABLE items(id integer PRIMARY KEY, note text UNIQUE NOT NULL);
-- seed
INSERT INTO items VALUES (1, 'seed');
-- begin
BEGIN;
-- trigger
INSERT INTO items VALUES (2, 'seed');
-- followup
SELECT 1 AS ignored;
-- rollback
ROLLBACK;
-- repair_begin
BEGIN;
-- repair
INSERT INTO items VALUES (2, 'repaired');
-- commit
COMMIT;
-- verify
SELECT id, note FROM items ORDER BY id;

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 {#versions}

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 {#related}

23505 unique violation, 25P01 no active SQL transaction, 40001 serialization failure.

Sources {#sources}

  • src.errcodes.18.6 (SHA-256 6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba)
  • src.calls.REL_18_6 — raw/calls/REL_18_6.jsonl (SHA-256 9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf)
  • src.postgres.18.6 (SHA-256 9fb62275b1badf94d01ab351337b60410cd9b3ab1fe63fa9f23d6d2185a21061)
  • doc.libpq.18.6 (SHA-256 a91ce8f29dde162245d2f35f839e8b7192f62a57e01020b80564af65edd09440) · official documentation

Compare versions

SQLSTATE evidence and recorded runtime versions

cases · failed_transaction_recovery
{
  "assertions": [
    "The root duplicate is 23505",
    "The follow-up command reports 25P02",
    "The failed transaction remains INERROR until ROLLBACK",
    "A new explicit transaction commits the repaired row"
  ],
  "case_id": "failed_transaction_recovery",
  "cleanup": "Drop the case schema with an owner connection.",
  "has_snippet": true,
  "position": 0,
  "preconditions": [
    "A runner-owned disposable target is provisioned."
  ],
  "repair": "Follow the explicit transaction or source boundary described by the case.",
  "trigger": "Raise a root unique violation, then issue a query before ROLLBACK.",
  "versions": [
    "10",
    "18"
  ]
}
claims · identity
{
  "claim_id": "identity",
  "limits": "It describes the transaction state after a prior error; it is often a secondary diagnostic.",
  "method": "Read the fixed condition row and macro.",
  "position": 0,
  "runtime": [],
  "sources": [
    "src.errcodes.18.6"
  ],
  "statement": "25P02 is in_failed_sql_transaction in Class 25."
}
claims · abort-state
{
  "claim_id": "abort-state",
  "limits": "The first error remains the root cause; 25P02 tells the client to stop issuing ordinary work and end the transaction.",
  "method": "Trace IsAbortedTransactionBlockState and the libpq PQTRANS_INERROR state.",
  "position": 1,
  "runtime": [],
  "sources": [
    "src.postgres.18.6",
    "src.calls.REL_18_6",
    "doc.libpq.18.6"
  ],
  "statement": "After an error aborts a transaction block, postgres.c rejects subsequent commands with 25P02 until COMMIT/ROLLBACK ends the block."
}
claims · runtime
{
  "claim_id": "runtime",
  "limits": "The repair demonstrates transaction-state recovery; it does not make the original duplicate valid.",
  "method": "Read the selected summaries and structured diagnostics.",
  "position": 2,
  "runtime": [],
  "sources": [
    "runtime",
    "runtime.25P02-batch2-latest-20260909.latest",
    "runtime.25P02-batch2-pg10-20260909.pg10"
  ],
  "statement": "The selected case first raises 23505, then observes 25P02 while INERROR, rolls back to IDLE, and commits a valid row in a new explicit transaction on both targets."
}
messages · aborted
{
  "limits": "The message is secondary to the earlier statement error; errdetail_abort may add context.",
  "message_id": "aborted",
  "path": "",
  "position": 0,
  "raw": {
    "id": "aborted",
    "limits": "The message is secondary to the earlier statement error; errdetail_abort may add context.",
    "primary_template": "current transaction is aborted, commands ignored until end of transaction block",
    "severity_source": "ERROR",
    "sources": [
      "src.postgres.18.6"
    ],
    "sqlstate": "25P02"
  },
  "severity": "ERROR",
  "sources": [
    "src.postgres.18.6"
  ],
  "templates": [
    {
      "kind": "primary",
      "literal": "current transaction is aborted, commands ignored until end of transaction block",
      "position": 0,
      "role": "",
      "template": "current transaction is aborted, commands ignored until end of transaction block"
    }
  ]
}
runtimes · runtime.25P02-batch2-latest-20260909.latest · 18.6 (Homebrew) · passed
{
  "cases": [
    "failed_transaction_recovery"
  ],
  "limits": "",
  "position": 0,
  "raw": {
    "case_manifest": {
      "path": "verify/cases/25P02/cases.json",
      "sha256": "dc6dea41ff7dc64f413c290151ee8200b11d66050eb5de499c64ef7aaf87f88c"
    },
    "case_status": "passed",
    "cases": [
      "failed_transaction_recovery"
    ],
    "id": "runtime.25P02-batch2-latest-20260909.latest",
    "observed": {
      "after_25P02": "INERROR",
      "after_rollback": "IDLE",
      "after_root_error": "INERROR",
      "final_status": "IDLE",
      "primary": "current transaction is aborted, commands ignored until end of transaction block",
      "root_primary": "duplicate key value violates unique constraint \"items_note_key\"",
      "root_sqlstate": "23505",
      "rows_after_retry": [
        [
          1,
          "seed"
        ],
        [
          2,
          "repaired"
        ]
      ],
      "sqlstate": "25P02"
    },
    "raw": "verify/results/25P02-batch2-latest-20260909/latest/raw.jsonl",
    "raw_sha256": "f03391117a5430c0611c72a1fa03ee6169f72575e69733a98023b0c9fb255788",
    "run_id": "25P02-batch2-latest-20260909",
    "server_version": "18.6 (Homebrew)",
    "server_version_num": 180006,
    "snippet_registry": {
      "path": "verify/cases/25P02/snippets.json",
      "sha256": "04da3240dcf3c03fe60d13715f8187350fadf5b8d1f10e5b837acd45289759cd"
    },
    "status": "passed",
    "summary": "verify/results/25P02-batch2-latest-20260909/latest/summary.json",
    "summary_sha256": "6c06ba72ebf7ce12c171d8a45ceec233b03eedc0db98796221d00c8b0e34732d",
    "target": "latest",
    "target_status": "passed"
  },
  "run_id": "25P02-batch2-latest-20260909",
  "runtime_id": "runtime.25P02-batch2-latest-20260909.latest",
  "server_version": "18.6 (Homebrew)",
  "status": "passed",
  "target": "latest"
}
runtimes · runtime.25P02-batch2-pg10-20260909.pg10 · 10.21 (Debian 10.21-1.pgdg90+1) · passed
{
  "cases": [
    "failed_transaction_recovery"
  ],
  "limits": "",
  "position": 1,
  "raw": {
    "case_manifest": {
      "path": "verify/cases/25P02/cases.json",
      "sha256": "dc6dea41ff7dc64f413c290151ee8200b11d66050eb5de499c64ef7aaf87f88c"
    },
    "case_status": "passed",
    "cases": [
      "failed_transaction_recovery"
    ],
    "id": "runtime.25P02-batch2-pg10-20260909.pg10",
    "observed": {
      "after_25P02": "INERROR",
      "after_rollback": "IDLE",
      "after_root_error": "INERROR",
      "final_status": "IDLE",
      "primary": "current transaction is aborted, commands ignored until end of transaction block",
      "root_primary": "duplicate key value violates unique constraint \"items_note_key\"",
      "root_sqlstate": "23505",
      "rows_after_retry": [
        [
          1,
          "seed"
        ],
        [
          2,
          "repaired"
        ]
      ],
      "sqlstate": "25P02"
    },
    "raw": "verify/results/25P02-batch2-pg10-20260909/pg10/raw.jsonl",
    "raw_sha256": "97d4ce9f816c98c09408bd00921a97e33708ccf52ca10da0682ab7238ef377a6",
    "run_id": "25P02-batch2-pg10-20260909",
    "server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
    "server_version_num": 100021,
    "snippet_registry": {
      "path": "verify/cases/25P02/snippets.json",
      "sha256": "04da3240dcf3c03fe60d13715f8187350fadf5b8d1f10e5b837acd45289759cd"
    },
    "status": "passed",
    "summary": "verify/results/25P02-batch2-pg10-20260909/pg10/summary.json",
    "summary_sha256": "722e8d8c8ddc1301c1c7acb98d9e6442dde6f3a2020246b30775dec8c98a3847",
    "target": "pg10",
    "target_status": "passed"
  },
  "run_id": "25P02-batch2-pg10-20260909",
  "runtime_id": "runtime.25P02-batch2-pg10-20260909.pg10",
  "server_version": "10.21 (Debian 10.21-1.pgdg90+1)",
  "status": "passed",
  "target": "pg10"
}
sources · src.errcodes.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "upstream_source",
  "location": "",
  "path": "src/backend/utils/errcodes.txt",
  "position": 0,
  "sha256": "6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba",
  "source_id": "src.errcodes.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt"
}
sources · src.calls.REL_18_6
{
  "commit": "",
  "docs_url": "",
  "kind": "local_artifact",
  "location": "",
  "path": "raw/calls/REL_18_6.jsonl",
  "position": 1,
  "sha256": "9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf",
  "source_id": "src.calls.REL_18_6",
  "tag": "",
  "url": ""
}
sources · src.postgres.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "",
  "kind": "upstream_source",
  "location": "",
  "path": "src/backend/tcop/postgres.c",
  "position": 2,
  "sha256": "9fb62275b1badf94d01ab351337b60410cd9b3ab1fe63fa9f23d6d2185a21061",
  "source_id": "src.postgres.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/tcop/postgres.c#L1127-L1140"
}
sources · doc.libpq.18.6
{
  "commit": "724edf9bde9d356724ad384a2e196edc3c9f80f7",
  "docs_url": "https://www.postgresql.org/docs/18/libpq-status.html",
  "kind": "upstream_source",
  "location": "",
  "path": "doc/src/sgml/libpq.sgml",
  "position": 3,
  "sha256": "a91ce8f29dde162245d2f35f839e8b7192f62a57e01020b80564af65edd09440",
  "source_id": "doc.libpq.18.6",
  "tag": "REL_18_6",
  "url": "https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/libpq.sgml#L2818-L2835"
}

Source references

Full definition and evidence JSON

Definition sources

center · PostgreSQL 18 · english-manuals:71cbabe45a6cf257be8691b85a72a43985b2835a07e2e1234a2922de8a3de492

Text language: en · english-manuals:71cbabe45a6cf257be8691b85a72a43985b2835a07e2e1234a2922de8a3de492