This error occurs when PostgreSQL cannot start a new transaction because one is already active in the same XA transaction branch. It commonly happens in distributed transaction scenarios with multiple resources.
Error code 25002 (BRANCH_TRANSACTION_ALREADY_ACTIVE) indicates that PostgreSQL is unable to start a new transaction because one is already active in the same branch. This error is specific to XA (eXtended Architecture) transactions, which are used in distributed transaction processing across multiple databases or resources. In XA transaction management, a "branch" represents a specific transaction context within a distributed transaction. Each branch must have only one active transaction at a time. When an application or transaction manager attempts to start a new transaction on a branch that already has an active transaction, PostgreSQL throws this error to prevent transaction state corruption. This error typically occurs in Java applications using JTA/XA with application servers (like JBoss EAP, WildFly, or WebLogic), in microservices architectures with distributed transactions, or when using transaction managers like Atomikos or Narayana with PostgreSQL.
Query the database to see all currently active transactions:
SELECT pid, usename, application_name, state, query_start, query
FROM pg_stat_activity
WHERE state = 'active'
AND pid = pg_backend_pid();This shows if your current connection has an active transaction that wasn't properly closed.
For all active transactions across the database:
SELECT pid, now() - pg_stat_activity.query_start AS duration, query
FROM pg_stat_activity
WHERE state = 'active'
ORDER BY duration DESC;If you have control over the session, explicitly end the current transaction:
-- If you want to commit the pending changes
COMMIT;
-- Or if you want to discard the changes
ROLLBACK;After this, you should be able to start a new transaction on the same branch.
Check your application code for proper transaction handling. Every transaction start must have a corresponding commit or rollback:
Java/JTA example:
UserTransaction ut = ...;
try {
ut.begin();
// Your database operations
ut.commit();
} catch (Exception e) {
ut.rollback(); // CRITICAL: Always rollback on error
throw e;
} finally {
// Ensure transaction is closed
}Common mistakes:
- Missing rollback in exception handlers
- Early returns that skip transaction cleanup
- Nested transaction attempts on the same connection
XA transactions require the max_prepared_transactions parameter to be set. Edit postgresql.conf:
max_prepared_transactions = 100 # Should be >= max_connectionsRestart PostgreSQL for changes to take effect:
sudo systemctl restart postgresqlVerify the setting:
SHOW max_prepared_transactions;If this is set to 0, XA transactions cannot work properly.
If using connection pooling (HikariCP, c3p0, DBCP), ensure connections are properly cleaned between uses:
HikariCP example (Java):
HikariConfig config = new HikariConfig();
config.setAutoCommit(true); // Auto-commit when connection is returned
config.setConnectionTestQuery("SELECT 1");Configure connection validation:
- Test connections before use
- Set reasonable connection timeouts
- Enable auto-commit for non-XA connections
If a transaction is stuck and cannot be closed normally, you can terminate the backend process:
-- Find the process ID (pid) from pg_stat_activity
SELECT pg_terminate_backend(12345); -- Replace with actual pidWarning: This forcibly kills the connection and rolls back the transaction. Only use this for stuck sessions that cannot be recovered normally.
XA Transaction Architecture:
XA transactions follow the two-phase commit (2PC) protocol. A transaction manager coordinates multiple resource managers (databases) through PREPARE and COMMIT phases. PostgreSQL acts as one resource manager in this distributed transaction.
Replication Limitations:
Error 25002 can occur when trying to use logical replication filters with XA transactions. PostgreSQL does not support replication filters for XA/prepared transactions. If you need both features, consider using separate connections for XA operations versus replicated data changes.
Transaction Isolation Levels:
XA transactions in PostgreSQL use the serializable isolation level by default. This can increase the likelihood of transaction conflicts in high-concurrency scenarios. Consider your isolation level requirements when designing distributed transactions.
Monitoring Prepared Transactions:
Monitor prepared transactions that haven't been committed or rolled back:
SELECT gid, prepared, owner, database
FROM pg_prepared_xacts
WHERE prepared < now() - interval '1 hour';Prepared transactions that remain for extended periods indicate transaction manager failures or application bugs that need investigation.
Connection State Management:
In pooled environments, always reset connection state when connections are returned to the pool. This includes rolling back any uncommitted transactions, resetting session variables, and clearing temporary tables.
insufficient columns in unique constraint for partition key
How to fix "insufficient columns in unique constraint for partition key" in PostgreSQL
ERROR 42501: must be owner of table
How to fix "must be owner of table" in PostgreSQL
trigger cannot change partition destination
How to fix "Trigger cannot change partition destination" in PostgreSQL
SSL error: certificate does not match host name
SSL error: certificate does not match host name in PostgreSQL
No SSL connection
No SSL connection to PostgreSQL