{"record":{"id":"43c2d5c32f4cd715","repo":"tursodatabase/turso","slug":"type-conversion-failed","errorCode":null,"errorMessage":"Type conversion failed: {}","messagePattern":"Type conversion failed: (.+?)","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/jdbc4/JDBC4ResultSet.java","lineNumber":1396,"sourceCode":"   *\n   * @param <T> the type of value to supply\n   */\n  @FunctionalInterface\n  public interface ResultSetSupplier<T> {\n    /**\n     * Gets a result from the result set.\n     *\n     * @return the result value\n     * @throws Exception if an error occurs\n     */\n    T get() throws Exception;\n  }\n\n  private <T> T wrapTypeConversion(ResultSetSupplier<T> supplier) throws SQLException {\n    try {\n      return supplier.get();\n    } catch (Exception e) {\n      throw new SQLException(\"Type conversion failed: \" + e);\n    }\n  }\n}\n","sourceCodeStart":1378,"sourceCodeEnd":1400,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/jdbc4/JDBC4ResultSet.java#L1378-L1400","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read each column with the getter that matches its storage class (INTEGER->getLong, REAL->getDouble, TEXT->getString, BLOB->getBytes)","Normalize in SQL with CAST(col AS INTEGER) / CAST(col AS TEXT) so the driver receives the expected type","Use rs.getObject(col), which performs no conversion, and convert yourself (instanceof on Long/Double/String/byte[])","Fix the data so a column holds one storage class; use typeof(col) in SQL to find offending rows"],"exampleFix":"// before: column stores TEXT\nint id = rs.getInt(\"id\"); // SQLException: Type conversion failed\n\n// after: cast in SQL, or read and parse\nint id = stmt.executeQuery(\"SELECT CAST(id AS INTEGER) AS id FROM t\")\n            .getInt(\"id\");\n// or\nObject v = rs.getObject(\"id\");\nint id = v instanceof Number n ? n.intValue() : Integer.parseInt(v.toString());","handlingStrategy":"validation","validationCode":"// getObject does no conversion: probe the storage class first\nObject v = rs.getObject(col);\nlong id;\nif (v instanceof Number n) {\n  id = n.longValue();\n} else if (v != null) {\n  id = Long.parseLong(v.toString());\n} else {\n  id = 0L; // NULL\n}","typeGuard":"private boolean readableAsLong(ResultSet rs, int col) throws SQLException {\n  Object v = rs.getObject(col);\n  return v == null || v instanceof Number;\n}","tryCatchPattern":"try {\n  return rs.getInt(col);\n} catch (SQLException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Type conversion failed\")) {\n    Object v = rs.getObject(col);\n    return v == null ? 0 : Integer.parseInt(v.toString()); // manual fallback\n  }\n  throw e;\n}","preventionTips":["Match getters to storage classes: INTEGER->getLong, REAL->getDouble, TEXT->getString, BLOB->getBytes","Use CAST(col AS ...) in the SELECT when a column's storage class does not match the reader you must use","Do not treat rs.getString as a universal getter on this driver; it fails on INTEGER/REAL values","Check typeof(col) in SQL when importing data to catch mixed-storage columns early"],"tags":["java","jdbc","turso","type-mismatch","class-cast-exception","dynamic-typing"],"backgroundTag":"type-conversion-failed","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}