tursodatabase/turso · error · java.sql.SQLException

ResultSet is null

Error message

ResultSet is null

What it means

get(int) requires a current row: lastStepResult must be non-null and its getResult() must be non-null. lastStepResult is only assigned inside next(), so this throw means a column was read before the first successful next() — the classic JDBC cursor-before-first-row misuse — or after a step that produced no row payload. It is a call-order bug, not an environment problem.

Solutions

  1. Always position the cursor first: if (rs.next()) { Object v = rs.get(1); }
  2. After TursoStatement.execute(), branch on its return value (or hasLastStepReturnedRow()) before reading columns
  3. Treat this error as a code bug to restructure, not a condition to catch and continue

Example fix

// before
boolean hasRow = stmt.execute();
Object v = rs.get(1); // throws when no row was stepped

// after
if (stmt.execute()) { // true: cursor sits on the first row
  Object v = rs.get(1);
}
Defensive patterns

Strategy: validation

Validate before calling

if (rs.next()) {
  Object v = rs.get(1);
} else {
  // no-row path
}

Try / catch

try {
  return rs.get(1);
} catch (SQLException e) {
  // reading before next() is a call-order bug: fix the order, never catch-and-continue
  throw new IllegalStateException("column read before next()", e);
}

Prevention

When it happens

Trigger: Calling rs.get(...) immediately after prepare/execute without a next() that returned true; ignoring execute()'s boolean return (which reflects whether the internal single step produced a row) and reading unconditionally; reading after next() returned false.

Common situations: Code ported from APIs with auto-positioned or 0-based cursors; single-row lookups where the author assumes execute positions the cursor; missing if (rs.next()) guard around single-row reads.

Related errors


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

Appendix: source

Thrown at bindings/java/src/main/java/tech/turso/core/TursoResultSet.java:165

  public Object get(String columnName) throws SQLException {
    final int columnsLength = this.columnNames.length;
    for (int i = 0; i < columnsLength; i++) {
      if (this.columnNames[i].equals(columnName)) {
        return get(i + 1);
      }
    }

    throw new SQLException("column name " + columnName + " not found");
  }

  public Object get(int columnIndex) throws SQLException {
    if (!this.isOpen()) {
      throw new SQLException("ResultSet is not open");
    }

    if (this.lastStepResult == null || this.lastStepResult.getResult() == null) {
      throw new SQLException("ResultSet is null");
    }

    final Object[] resultSet = this.lastStepResult.getResult();
    if (columnIndex > resultSet.length || columnIndex < 0) {
      throw new SQLException("columnIndex out of bound");
    }

    return resultSet[columnIndex - 1];
  }

  public String[] getColumnNames() {
    return this.columnNames;
  }

  public void setColumnNames(String[] columnNames) {
    this.columnNames = columnNames;
  }

View on GitHub (pinned to 244cde92a7)