{"record":{"id":"e57a8c21211be3e5","repo":"tursodatabase/turso","slug":"resultset-is-null","errorCode":null,"errorMessage":"ResultSet is null","messagePattern":"ResultSet is null","errorType":"exception","errorClass":"java.sql.SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/core/TursoResultSet.java","lineNumber":165,"sourceCode":"\n  public Object get(String columnName) throws SQLException {\n    final int columnsLength = this.columnNames.length;\n    for (int i = 0; i < columnsLength; i++) {\n      if (this.columnNames[i].equals(columnName)) {\n        return get(i + 1);\n      }\n    }\n\n    throw new SQLException(\"column name \" + columnName + \" not found\");\n  }\n\n  public Object get(int columnIndex) throws SQLException {\n    if (!this.isOpen()) {\n      throw new SQLException(\"ResultSet is not open\");\n    }\n\n    if (this.lastStepResult == null || this.lastStepResult.getResult() == null) {\n      throw new SQLException(\"ResultSet is null\");\n    }\n\n    final Object[] resultSet = this.lastStepResult.getResult();\n    if (columnIndex > resultSet.length || columnIndex < 0) {\n      throw new SQLException(\"columnIndex out of bound\");\n    }\n\n    return resultSet[columnIndex - 1];\n  }\n\n  public String[] getColumnNames() {\n    return this.columnNames;\n  }\n\n  public void setColumnNames(String[] columnNames) {\n    this.columnNames = columnNames;\n  }\n","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/java/src/main/java/tech/turso/core/TursoResultSet.java#L147-L183","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Always position the cursor first: if (rs.next()) { Object v = rs.get(1); }","After TursoStatement.execute(), branch on its return value (or hasLastStepReturnedRow()) before reading columns","Treat this error as a code bug to restructure, not a condition to catch and continue"],"exampleFix":"// before\nboolean hasRow = stmt.execute();\nObject v = rs.get(1); // throws when no row was stepped\n\n// after\nif (stmt.execute()) { // true: cursor sits on the first row\n  Object v = rs.get(1);\n}","handlingStrategy":"validation","validationCode":"if (rs.next()) {\n  Object v = rs.get(1);\n} else {\n  // no-row path\n}","typeGuard":null,"tryCatchPattern":"try {\n  return rs.get(1);\n} catch (SQLException e) {\n  // reading before next() is a call-order bug: fix the order, never catch-and-continue\n  throw new IllegalStateException(\"column read before next()\", e);\n}","preventionTips":["Always gate reads on next() == true (or execute()'s true return)","For single-row lookups, write if (rs.next()) { ... } else { not-found } every time","Treat 'ResultSet is null' as a logic bug, not a runtime condition to handle"],"tags":["java","jdbc","result-set","cursor","call-order"],"backgroundTag":"cursor-before-first-row","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}