tursodatabase/turso · error · SQLException

SQL command cannot be null

Error message

SQL command cannot be null

What it means

JDBC4Statement.addBatch(String) first checks the statement is open (ensureOpen), then rejects a null SQL string with SQLException("SQL command cannot be null") before appending to batchCommands. clearBatch empties the list and executeBatch runs it; the null check exists so a null never silently lands in the batch.

Solutions

  1. Null-check (and ideally blank-check) each SQL string before addBatch
  2. Skip the record entirely when SQL generation produced nothing
  3. Guard the whole batch loop when the source collection may contain nulls

Example fix

// before
for (String sql : statements) {
  stmt.addBatch(sql); // NPE-adjacent entry -> SQLException on null
}

// after
for (String sql : statements) {
  if (sql == null || sql.isBlank()) continue;
  stmt.addBatch(sql);
}
Defensive patterns

Strategy: validation

Validate before calling

for (String sql : statements) {
  if (sql != null && !sql.isBlank()) {
    stmt.addBatch(sql);
  }
}

Try / catch

try {
  stmt.addBatch(sql);
} catch (SQLException e) {
  if ("SQL command cannot be null".equals(e.getMessage())) {
    continue; // skip the offending entry
  }
  throw e;
}

Prevention

When it happens

Trigger: stmt.addBatch(null); loops building batches from lists/maps where some entries are null; SQL builders that return null on an error path; conditional generation where the 'no SQL produced' case yields null instead of being skipped.

Common situations: Batch importers iterating nullable records; refactors that moved null-filtering after the addBatch call; test code passing null to mean 'skip this one'.

Related errors


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

Appendix: source

Thrown at bindings/java/src/main/java/tech/turso/jdbc4/JDBC4Statement.java:265

    // TODO
    return 0;
  }

  @Override
  public int getResultSetConcurrency() {
    return resultSetConcurrency;
  }

  @Override
  public int getResultSetType() {
    return resultSetType;
  }

  @Override
  public void addBatch(String sql) throws SQLException {
    ensureOpen();
    if (sql == null) {
      throw new SQLException("SQL command cannot be null");
    }
    batchCommands.add(sql);
  }

  @Override
  public void clearBatch() throws SQLException {
    ensureOpen();
    batchCommands.clear();
  }

  // TODO: let's make this batch operation atomic
  @Override
  public int[] executeBatch() throws SQLException {
    ensureOpen();

    int[] updateCounts = new int[batchCommands.size()];
    List<String> failedCommands = new ArrayList<>();

View on GitHub (pinned to 244cde92a7)