tursodatabase/turso · error · SQLException

Invalid transaction isolation level: ${level}

Error message

Invalid transaction isolation level: ${level}

What it means

TursoConnection.setTransactionIsolation() only accepts the four java.sql.Connection constants: TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE. Any other int (custom value, vendor-specific constant, or garbage from config) is rejected.

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 bad083fafb)

Solutions

  1. Use Connection.TRANSACTION_SERIALIZABLE — SQLite/Turso effectively serialize writers, so it is the accurate value
  2. Validate the value against the four constants before calling setTransactionIsolation
  3. Check the config source for typos or values carried over from a previous database

Example fix

// before
conn.setTransactionIsolation(4096); // vendor constant from an old SQL Server app

// after
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
Defensive patterns

Strategy: validation

Validate before calling

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

if (!SUPPORTED.contains(level)) {
  throw new IllegalArgumentException("Unsupported isolation level: " + level);
}
conn.setTransactionIsolation(level);

Type guard

static boolean isValidIsolationLevel(int level) {
  return level == Connection.TRANSACTION_READ_UNCOMMITTED
      || level == Connection.TRANSACTION_READ_COMMITTED
      || level == Connection.TRANSACTION_REPEATABLE_READ
      || level == Connection.TRANSACTION_SERIALIZABLE;
}

Prevention

When it happens

Trigger: Passing a database-specific constant such as a vendor snapshot-isolation value (e.g. 4096), an arbitrary int like 8, or a config-derived number that failed to parse into one of the four accepted constants (0, 1, 2, 4, 8).

Common situations: Porting isolation settings from SQL Server/Oracle constant tables; typos in YAML/properties files (transcation_serializable, wrong numeric); mapping code that reads another database's metadata and forwards it verbatim.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/d8693f1fe70c9091. Report an issue: GitHub.