The real issue: psycopg2 operates in "implicit transaction" mode by default. Every query — even a simple SELECT — starts a transaction. So after runWithConnection runs a SELECT, the connection is "in a transaction" even though nothing needs committing. Twisted's
ConnectionPool.runWithConnection handled this by calling rollback() after each runWithConnection call to close the implicit transaction.
The fix should be: commit/rollback after runWithConnection completes (not before the next call), matching Twisted's behavior: