{"record":{"id":"3078e5656e53dbca","repo":"tursodatabase/turso","slug":"failed-to-convert-sql-into-bytes","errorCode":null,"errorMessage":"Failed to convert ${sql} into bytes","messagePattern":"Failed to convert (.+?) into bytes","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/core/TursoConnection.java","lineNumber":135,"sourceCode":"  /**\n   * Compiles an SQL statement with optional transaction start check.\n   *\n   * @param sql An SQL statement.\n   * @param checkTransaction Whether to check and start transaction if needed.\n   * @return Pointer to statement.\n   * @throws SQLException if a database access error occurs.\n   */\n  private TursoStatement prepare(String sql, boolean checkTransaction) throws SQLException {\n    logger.trace(\"DriverManager [{}] [SQLite EXEC] {}\", Thread.currentThread().getName(), sql);\n\n    // Ensure transaction is started if needed (lazy transaction start)\n    if (checkTransaction) {\n      ensureTransactionStarted(sql);\n    }\n\n    byte[] sqlBytes = stringToUtf8ByteArray(sql);\n    if (sqlBytes == null) {\n      throw new SQLException(\"Failed to convert \" + sql + \" into bytes\");\n    }\n    return new TursoStatement(sql, prepareUtf8(connectionPtr, sqlBytes));\n  }\n\n  private native long prepareUtf8(long connectionPtr, byte[] sqlUtf8) throws SQLException;\n\n  // TODO: check whether this is still valid for turso\n  /**\n   * Checks whether the type, concurrency, and holdability settings for a {@link ResultSet} are\n   * supported by the SQLite interface. Supported settings are:\n   *\n   * <ul>\n   *   <li>type: {@link ResultSet#TYPE_FORWARD_ONLY}\n   *   <li>concurrency: {@link ResultSet#CONCUR_READ_ONLY})\n   *   <li>holdability: {@link ResultSet#CLOSE_CURSORS_AT_COMMIT}\n   * </ul>\n   *\n   * @param resultSetType the type setting.","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/core/TursoConnection.java#L117-L153","documentation":"SQLException thrown in TursoConnection.prepare when stringToUtf8ByteArray(sql) returns null — which happens only when the SQL string itself is null. The statement text must be UTF-8 encoded bytes before being passed to the native prepareUtf8, so a null statement cannot be compiled and is rejected with this message (the runtime text interpolates the null sql).","triggerScenarios":"conn.prepare(null) or createStatement-level paths passing a null SQL string; a String variable that is null because a lookup, config key, or optional mapping produced nothing; an ORM/query-builder path that forwards null for a skipped query.","commonSituations":"Optional SQL sourced from configuration that was never set; refactors that moved SQL constants and left a null default; NPE-avoidance patterns that substitute null and push the failure to prepare time.","solutions":["Null-check the SQL before preparing and fail fast with a meaningful application error or skip the statement","Trace the null to its source — usually a missing config value or an absent mapping","Make SQL constants non-null final so absence is caught at startup, not at query time"],"exampleFix":"// before\nString sql = config.get(\"query.delete\"); // null when the key is missing\ntry (TursoStatement st = conn.prepare(sql)) { st.execute(); } // Failed to convert null into bytes\n\n// after\nString sql = Objects.requireNonNull(config.get(\"query.delete\"), \"missing query.delete config\");\ntry (TursoStatement st = conn.prepare(sql)) { st.execute(); }","handlingStrategy":"validation","validationCode":"if (sql == null || sql.isBlank()) {\n  throw new SQLException(\"SQL must be a non-empty string\");\n}\ntry (TursoStatement st = conn.prepare(sql)) {\n  st.execute();\n}","typeGuard":"static boolean isPreparable(String sql) {\n  return sql != null && !sql.isBlank();\n}","tryCatchPattern":null,"preventionTips":["Make SQL constants non-null final and fail fast at config load when one is missing","Reject null at your API boundary with a clear application error instead of letting it reach prepare","Lint for config.get(...) values used directly as SQL without null checks"],"tags":["java","jdbc","null-safety"],"backgroundTag":"null-argument","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}