tursodatabase/turso · error · SQLException
Cannot change isolation level while transaction is active.
Error message
Cannot change isolation level while transaction is active.
What it means
setTransactionIsolation() refuses to run while a transaction is active on the connection. Transactions begin lazily: once setAutoCommit(false) is set, the first prepared non-BEGIN/COMMIT/ROLLBACK statement starts one, and from that moment changing the isolation level is disallowed until you commit or roll back.
Solutions
- Set the isolation level before any statement executes: right after getConnection and setAutoCommit(false), before the first prepare
- Clean connections before returning them to a pool: rollback any pending work (rollback() is a safe no-op when autoCommit is false and no transaction started)
- In pool reset logic, order operations: rollback first, then setAutoCommit, then setTransactionIsolation
Example fix
// before conn.setAutoCommit(false); executeWork(conn); // lazy BEGIN fires here conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); // throws // after conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); conn.setAutoCommit(false); executeWork(conn); conn.commit();
Defensive patterns
Strategy: validation
Validate before calling
// reset to a clean state before changing isolation
if (!conn.getAutoCommit()) {
conn.rollback(); // clears any lazily-started transaction (no-op if none started)
}
conn.setTransactionIsolation(level); Try / catch
try {
conn.setTransactionIsolation(level);
} catch (SQLException e) {
if (e.getMessage().contains("transaction is active")) {
if (!conn.getAutoCommit()) conn.rollback();
conn.setTransactionIsolation(level); // retry once on a clean connection
}
throw e;
} Prevention
- Configure isolation immediately after getConnection, before setAutoCommit(false) and any statement
- Always return pooled connections clean: rollback pending work before handback
- Order pool reset as rollback -> setAutoCommit -> setTransactionIsolation
- Remember the lazy-BEGIN rule: with autoCommit off, ANY executed statement opens the transaction that blocks the change
When it happens
Trigger: Calling setTransactionIsolation after setAutoCommit(false) plus any statement; connection pools calling setTransactionIsolation on checkout when the previous borrower left a transaction open (no commit/rollback before return); changing isolation mid-unit-of-work.
Common situations: Pool adapters (DBCP, HikariCP-style wrappers) that reset isolation on borrow and hit connections returned dirty; application code that begins work, then configures isolation; error paths that skip the cleanup rollback.
Related errors
- Cannot commit in autocommit mode.
- Cannot rollback in autocommit mode.
- Failed to rollback transaction during close
- Invalid transaction isolation level
- Statement is closed
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/4f880e0a5e354494.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/java/src/main/java/tech/turso/core/TursoConnection.java:294
}
}
/**
* Sets the transaction isolation level.
*
* @param level one of the following {@code Connection} constants: {@code
* Connection.TRANSACTION_READ_UNCOMMITTED}, {@code Connection.TRANSACTION_READ_COMMITTED},
* {@code Connection.TRANSACTION_REPEATABLE_READ}, or {@code
* Connection.TRANSACTION_SERIALIZABLE}.
* @throws SQLException if a database access error occurs, this method is called on a closed
* connection or the given parameter is not one of the {@code Connection} constants
*/
public void setTransactionIsolation(int level) throws SQLException {
synchronized (transactionLock) {
checkOpen();
if (inTransaction) {
throw new SQLException("Cannot change isolation level while transaction is active.");
}
if (level != Connection.TRANSACTION_READ_UNCOMMITTED
&& level != Connection.TRANSACTION_READ_COMMITTED
&& level != Connection.TRANSACTION_REPEATABLE_READ
&& level != Connection.TRANSACTION_SERIALIZABLE) {
throw new SQLException("Invalid transaction isolation level: " + level);
}
this.transactionIsolation = level;
}
}
/**
* Retrieves the current transaction isolation level.
*
* @return the current transaction isolation level
* @throws SQLException if a database access error occurs or the connection is closedView on GitHub (pinned to 244cde92a7)