Incident brief
Current transaction is aborted, commands ignored until end of transaction block
One statement inside a transaction failed. PostgreSQL now rejects every later command in that same transaction until it sees ROLLBACK, even if those later commands are perfectly valid on their own.
What lands in your log
ERROR: division by zero
In 10 seconds
- What triggers it
- Start a transaction with BEGIN.
- Fix
- ROLLBACK the transaction and start again.
- Proof
- Reproduced on PostgreSQL 16.14 → The division-by-zero error aborted the transaction. The next INSERT was rejected even though it is a valid statement on its own, and ROLLBACK discarded both inserts, the table ended up empty.
Fix
What to do right now
Application-level steps for this error.
- ROLLBACK the transaction and start again.
- Or place a SAVEPOINT before risky statements so you can ROLLBACK TO the savepoint instead of losing everything.
- Stop sending commands as soon as the first error appears. They will all be rejected until ROLLBACK.
BEGIN;
INSERT INTO finance.ledger (id, amount) VALUES (10, 100);
SAVEPOINT before_risky;
-- a statement that might fail goes here
ROLLBACK TO SAVEPOINT before_risky;
-- the transaction is usable again
INSERT INTO finance.ledger (id, amount) VALUES (11, 50);
COMMIT;For this error
See this error live on the server
Run these against the affected instance to confirm the diagnosis before you act.
25P02 is a consequence, not the first failure. The current session must ROLLBACK; diagnose the first SQLSTATE in the same transaction from application/server logs.
Transaction age for the affected backend
Confirm the connection is still sitting in a transaction while the application keeps sending commands.
SELECT pid, usename, application_name, state,
now() - xact_start AS transaction_age,
left(query, 120) AS last_query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_start;Why it happens
What PostgreSQL is telling you
The mechanism behind the error, grounded in the official manual, not paraphrased.
PostgreSQL 16 Documentation, §3.4 Transactions (Savepoints)
ROLLBACK TO is the only way to regain control of a transaction block that was put in aborted state by the system due to an error, short of rolling it back completely and starting again.Read the full section on postgresql.org →
The transaction (fails partway through)
The division by zero is a real error, so PostgreSQL marks the whole transaction as aborted. The second INSERT is completely valid SQL, but SQLSTATE 25P02 says PostgreSQL will not even try to run it, the only way out of an aborted transaction is ROLLBACK (or ROLLBACK TO a savepoint).Checking the table afterward
The table is empty. ROLLBACK undid the first INSERT too, because both statements were inside the same transaction that never committed. Nothing was ever saved.Reproduce & verify
A real, single-session PostgreSQL reproduction
A literal transcript of SQL run against a live PostgreSQL instance in an isolated lab. The commands below are exactly what was executed.
- 1Start a transaction with BEGIN.
- 2Run one statement that succeeds, for example an INSERT.
- 3Run a statement that fails, for example a division by zero.
- 4Try to run another normal statement in the same transaction.
- 5PostgreSQL rejects it with SQLSTATE 25P02, even though that statement is fine on its own.
One client, one transaction: a valid insert, then a failing statement, then another valid insert, then ROLLBACK.
CREATE SCHEMA IF NOT EXISTS finance;
DROP TABLE IF EXISTS finance.ledger;
CREATE TABLE finance.ledger (
id integer primary key,
amount integer not null
);BEGIN;
INSERT INTO finance.ledger (id, amount) VALUES (1, 100);
-- this line breaks: division by zero
SELECT 1/0;
-- the transaction is now aborted; this normal insert is rejected too
INSERT INTO finance.ledger (id, amount) VALUES (2, 50);
ROLLBACK;SELECT * FROM finance.ledger ORDER BY id;What PostgreSQL actually returned
DROP TABLE
CREATE TABLEBEGIN
INSERT 0 1
ERROR: division by zero
ERROR: current transaction is aborted, commands ignored until end of transaction block
ROLLBACK id | amount
----+--------
(0 rows)A SAVEPOINT placed before the risky statement lets a transaction recover from an error without losing everything already done. This was run against the same failure to prove it actually works.
Without this
Above: without a savepoint, the error aborted the whole transaction and ROLLBACK discarded both inserts.
With this, tested
Below: with a savepoint before the risky statement, only the risky part was undone, the transaction recovered and committed.
- A second operational test: exact SQL, raw output, measured result, and engineer notes
- A captured monitoring query with its raw output
- Fix that looks safe but is not: exact SQL, output, and verdict
- A manual-grounded production interpretation of the lab result
Card required. Cancel before day 7 and you are not charged.
Runbook to fix this
Runbooks for this incident
Full step-by-step fixes for the condition behind this error: the diagnosis, the exact SQL, and output captured in the lab.
- Diagnose PgBouncer queueing and session-state leaksClients wait in PgBouncer even though PostgreSQL has capacity, or session settings behave inconsistently.Free
- Catch a high transaction rollback rateA retry loop quietly rolls back four transactions in ten and everything looks fine.Pro
- Stop idle-in-transaction sessions from holding locksA session sits idle in transaction, holding its locks and pinning vacuum.Pro
Connected
Everything this error touches
Every page this SQLSTATE connects to: the concept that explains it, the runbooks that fix it, the parameters you tune to prevent it, and the sibling errors it travels with. All real cross-references. Jump straight in, or open the full interactive map.
Understand the concept
Fix it — runbooks
Related errors
Verification
- Last verified
- 2026-07-15 (Docker lab, PostgreSQL 16.14)
- Verification scope
- Verified against PostgreSQL 16.14 in an isolated lab environment
- Audit status
- reviewed
Went further?
Pro unlocks the second lab proof
Free page stops the bleeding. Pro adds the operational test, SQLSTATE audit, and deeper evidence, same error, more certainty.