tursodatabase/turso · error · SQLException

Type conversion failed: {}

Error message

Type conversion failed: {}

What it means

Every typed getter on JDBC4ResultSet (getString, getBoolean, getByte, getShort, getInt, getLong, getFloat, getDouble, getBigDecimal, getBytes, date/time getters, getCharacterStream) reads the raw Turso value and casts it directly: INTEGER arrives as Long, REAL as Double, TEXT as String, BLOB as byte[]. wrapTypeConversion wraps what the cast throws — usually ClassCastException — into SQLException("Type conversion failed: " + e). NULL is handled before the cast, so this error is always a storage-class/getter mismatch, never a null.

Source

Thrown at bindings/java/src/main/java/tech/turso/jdbc4/JDBC4ResultSet.java:1396

   *
   * @param <T> the type of value to supply
   */
  @FunctionalInterface
  public interface ResultSetSupplier<T> {
    /**
     * Gets a result from the result set.
     *
     * @return the result value
     * @throws Exception if an error occurs
     */
    T get() throws Exception;
  }

  private <T> T wrapTypeConversion(ResultSetSupplier<T> supplier) throws SQLException {
    try {
      return supplier.get();
    } catch (Exception e) {
      throw new SQLException("Type conversion failed: " + e);
    }
  }
}

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Read each column with the getter that matches its storage class (INTEGER->getLong, REAL->getDouble, TEXT->getString, BLOB->getBytes)
  2. Normalize in SQL with CAST(col AS INTEGER) / CAST(col AS TEXT) so the driver receives the expected type
  3. Use rs.getObject(col), which performs no conversion, and convert yourself (instanceof on Long/Double/String/byte[])
  4. Fix the data so a column holds one storage class; use typeof(col) in SQL to find offending rows

Example fix

// before: column stores TEXT
int id = rs.getInt("id"); // SQLException: Type conversion failed

// after: cast in SQL, or read and parse
int id = stmt.executeQuery("SELECT CAST(id AS INTEGER) AS id FROM t")
            .getInt("id");
// or
Object v = rs.getObject("id");
int id = v instanceof Number n ? n.intValue() : Integer.parseInt(v.toString());
Defensive patterns

Strategy: validation

Validate before calling

// getObject does no conversion: probe the storage class first
Object v = rs.getObject(col);
long id;
if (v instanceof Number n) {
  id = n.longValue();
} else if (v != null) {
  id = Long.parseLong(v.toString());
} else {
  id = 0L; // NULL
}

Type guard

private boolean readableAsLong(ResultSet rs, int col) throws SQLException {
  Object v = rs.getObject(col);
  return v == null || v instanceof Number;
}

Try / catch

try {
  return rs.getInt(col);
} catch (SQLException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Type conversion failed")) {
    Object v = rs.getObject(col);
    return v == null ? 0 : Integer.parseInt(v.toString()); // manual fallback
  }
  throw e;
}

Prevention

When it happens

Trigger: rs.getInt/getLong on a TEXT column, even when the text is '42' (the value is a String, the cast to Long fails); rs.getString on an INTEGER or REAL column (Long/Double cannot cast to String); getLong on a REAL column (Double to Long); getBoolean on non-INTEGER storage (the cast (Long) result); getBytes/getDate/getCharacterStream on a column that is not a BLOB/TEXT/TEXT respectively.

Common situations: Migrating from xerial sqlite-jdbc, which coerces lazily ('42' -> 42 works there but not here); reading CSV/imported data where everything landed as TEXT; using rs.getString(col) as a universal getter across mixed-type columns; ORM entity fields typed Long while the column stores REAL.

Related errors


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