How to fix 25002: branch_transaction_already_active in PostgreSQL
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.
Quick fix
Fixes 25002: branch_transaction_already_active
SELECT pid, usename, application_name, state, query_start, query
FROM pg_stat_activity
WHERE state = 'active'
AND pid = pg_backend_pid();- Identify active transactions on the connection
- Commit or rollback the existing transaction
- Review application transaction management code
- Configure max_prepared_transactions for XA support
SELECT pid, usename, application_name, state, query_start, queryFROM pg_stat_activityWHERE state = 'active'AND pid = pg_backend_pid();25002: branch_transaction_already_active
What this error means
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.
Typical symptoms
- XA transaction operations fail with SQLSTATE 25002
- Distributed transactions cannot be started in Java applications
- Application server logs show "branch_transaction_already_active" errors
- Transaction manager reports failures during transaction coordination
- Database connections appear to be "stuck" in an active transaction state
Common causes
- Previous transaction on the same XA branch was not properly committed or rolled back
- Application code starts a new transaction before closing the previous one
- Transaction manager fails to properly end transactions due to network issues or timeouts
- Connection pooling reuses connections with dangling transactions
- Exception handling in application code skips transaction cleanup (COMMIT or ROLLBACK)
- Replication filters are configured with XA transactions (not supported)
How to fix "25002: branch_transaction_already_active"
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.
Advanced notes
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.
Frequently asked questions
- What does "25002: branch_transaction_already_active" mean?
- 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.
- How do I fix "25002: branch_transaction_already_active"?
- 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.
- What causes "25002: branch_transaction_already_active"?
- Previous transaction on the same XA branch was not properly committed or rolled back Application code starts a new transaction before closing the previous one Transaction manager fails to properly end transactions due to network issues or timeouts
- Is the "25002: branch_transaction_already_active" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- ๐PostgreSQL Official Documentation
- ๐postgresql.org - errcodes appendix(Official Docs)
- ๐
- ๐postgresql.org - sql prepare transaction(Official Docs)
- ๐atomikos.com - ConfiguringPostgreSQL(Official Docs)
- ๐github.com - PGXAConnection.java(GitHub)