Postgres is complaining that a command was issued without an active transaction because the client library, or the application it’s talking to, is trying to send a command without first starting a transaction block.

Here are the common reasons this happens and how to fix them:

1. Autocommit is Off and No BEGIN Was Issued: Many client libraries default to autocommit being on, meaning each SQL statement is its own transaction. If autocommit is explicitly turned off in your connection settings or by a previous command, you must manually start a transaction with BEGIN (or START TRANSACTION) before executing any data-modifying statements.

  • Diagnosis: Connect to your database using psql and run SHOW autocommit;. If it’s off, this is likely your issue.
  • Fix: Before your application’s statements, ensure a BEGIN; statement is executed. In your application code, this often looks like a specific function call to start a transaction. For example, in Python with psycopg2, you’d typically use conn.autocommit = False and then conn.begin() or rely on the default behavior where conn.cursor() starts a transaction if autocommit is off.
  • Why it works: Explicitly starting a transaction block with BEGIN tells Postgres to group subsequent commands until a COMMIT or ROLLBACK.

2. Application Logic Error: Missing COMMIT or ROLLBACK: Your application might have started a transaction (BEGIN) but then encountered an error or a code path that doesn’t explicitly call COMMIT or ROLLBACK. Postgres will then hold the transaction open, and subsequent commands will fail with this "no transaction in progress" error if they are not part of that original transaction.

  • Diagnosis: Examine your application’s transaction handling logic. Look for BEGIN statements and ensure that every path that starts a transaction eventually leads to a COMMIT or ROLLBACK. Debugging your application’s control flow is key here.
  • Fix: Add COMMIT; or ROLLBACK; statements to all relevant code paths in your application. Use try...except...finally blocks to guarantee that a COMMIT or ROLLBACK is always executed, even if errors occur.
  • Why it works: This ensures that every transaction that is opened is properly terminated, either by saving the changes (COMMIT) or discarding them (ROLLBACK), preventing orphaned transactions.

3. Connection Pooling Issues: Stale or Abused Connections: If you’re using a connection pool, a connection might have been returned to the pool in an unexpected state. For instance, a transaction was left open on the connection, and the pool then gives that connection to a new request that expects a clean slate (or autocommit on).

  • Diagnosis: Configure your connection pool to log connection states or errors. Many pools have settings to "reset" a connection upon return, which can include aborting any open transactions. Check your pool’s documentation for options like reset_on_return or similar.
  • Fix: Configure your connection pool to automatically abort any open transactions when a connection is returned. For example, with pgbouncer, you might ensure client_idle_timeout is set appropriately, and that connections are periodically re-established. If using libraries like c3p0 or HikariCP for Java, look for validation queries or reset mechanisms.
  • Why it works: This cleans up any lingering transaction state on connections before they are reused, ensuring a fresh start for each new request.

4. SET Commands in an Interactive Session Without BEGIN: If you’re running SET commands (like SET search_path = 'my_schema'; or SET client_encoding = 'UTF8';) in a psql session where autocommit is off, and you haven’t issued a BEGIN, these SET commands themselves are considered commands that require a transaction.

  • Diagnosis: In psql, run SHOW autocommit;. If it’s off, then any SET command you run without a preceding BEGIN will cause this.
  • Fix: Either turn autocommit back on (SET autocommit = ON;) or, more robustly, wrap your SET commands within a transaction block: BEGIN; SET search_path = 'my_schema'; ...; COMMIT;.
  • Why it works: SET commands that affect the session state (like search_path or client_encoding) are transactional in Postgres. They need to be part of a transaction to ensure consistency.

5. Application Framework Defaults: Some application frameworks or ORMs might have their own transaction management layers. If these are misconfigured, or if you’re bypassing them for certain operations, you might end up with this error.

  • Diagnosis: Consult your framework’s documentation on transaction management. Look for how it handles BEGIN, COMMIT, and ROLLBACK, and what happens when exceptions occur.
  • Fix: Ensure you are correctly using the framework’s provided methods for starting, committing, and rolling back transactions. If you’re executing raw SQL, make sure you’re adhering to the framework’s transaction context.
  • Why it works: The framework’s transaction management ensures that Postgres commands are issued within the correct transactional boundaries.

6. PGStatement.execute() in Java (JDBC) Without Prepared Statement: In Java, if you’re using Statement.execute() and autocommit is off, and you haven’t explicitly started a transaction, the execute() call itself can trigger this. This is especially true if you’re running a command that could modify data but isn’t a SELECT.

  • Diagnosis: Review your Java JDBC code. If you have connection.setAutoCommit(false); and then use statement.execute(sqlCommand); without a preceding connection.commit(); or connection.rollback(); (or connection.savepoint() if using savepoints), this is the cause.
  • Fix: Ensure you call connection.commit(); after successful operations or connection.rollback(); in case of errors. Alternatively, if you want each statement to be its own transaction, set connection.setAutoCommit(true);.
  • Why it works: Similar to other scenarios, this enforces explicit transaction boundaries, which are required when autocommit is disabled.

The next error you’ll likely see after fixing these is a ROLLBACK due to a deadlock, or a FATAL: sorry, too many clients already if your connection management is also problematic.

Want structured learning?

Take the full Postgres course →