tursodatabase/turso · error · SQLException

Invalid transaction isolation level

Error message

Invalid transaction isolation level: {level}

What it means

Thrown by TursoConnection.setTransactionIsolation(int) when level is not one of the four accepted JDBC constants: TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, or TRANSACTION_SERIALIZABLE. The setter stores the level verbatim, so it validates the full domain up front under the transaction lock. Note that TRANSACTION_NONE (0), a standard JDBC constant, is rejected because the engine cannot disable isolation.

Solutions

  1. Pass exactly one of the four Connection constants listed in the check
  2. If you meant TRANSACTION_NONE, remove the call entirely: the engine has no dirty reads and the connection default is already fine
  3. Map free-form config strings/values to the four constants through an allowlist before calling the setter
  4. As a last resort, wrap the call in try-catch and fall back to the value returned by getTransactionIsolation()

Example fix

// before
conn.setTransactionIsolation(Connection.TRANSACTION_NONE); // throws

// after
// TRANSACTION_NONE is not supported; only these four are accepted
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
Defensive patterns

Strategy: validation

Validate before calling

private static final Set<Integer> SUPPORTED_ISOLATION = Set.of(
    Connection.TRANSACTION_READ_UNCOMMITTED,
    Connection.TRANSACTION_READ_COMMITTED,
    Connection.TRANSACTION_REPEATABLE_READ,
    Connection.TRANSACTION_SERIALIZABLE);

if (!SUPPORTED_ISOLATION.contains(level)) {
  throw new IllegalArgumentException(
      "level must be one of the four JDBC isolation constants, got: " + level);
}
conn.setTransactionIsolation(level);

Try / catch

try {
  conn.setTransactionIsolation(level);
} catch (SQLException e) {
  // keep the current level; surface a clear config error instead of a generic SQLException
  throw new ConfigurationException("unsupported isolation level: " + level, e);
}

Prevention

When it happens

Trigger: Calling conn.setTransactionIsolation(level) with Connection.TRANSACTION_NONE, an arbitrary int (e.g. 5 or -1), or a value read from configuration that is not exactly one of the four accepted constants. Calling it while a transaction is active throws a different message first ('Cannot change isolation level while transaction is active.').

Common situations: Ported JDBC code that defaults to TRANSACTION_NONE; passing a connection-pool property (e.g. HikariCP's transactionIsolation) straight through as an int; constants renamed or mistyped after a refactor; code written for PostgreSQL/MySQL where NONE is accepted.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/a1ce0edc7f082d58. Report an issue: GitHub.

Appendix: source

Thrown at bindings/java/src/main/java/tech/turso/core/TursoConnection.java:301

   *     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 closed
   */
  public int getTransactionIsolation() throws SQLException {
    checkOpen();
    return transactionIsolation;
  }

  /**

View on GitHub (pinned to 244cde92a7)