pentaho/pentaho-kettle · warning · KettleDatabaseException

Couldn't close query: resultset or prepared statements

Error message

Couldn't close query: resultset or prepared statements

What it means

closeQuery() closes the ResultSet and PreparedStatement of an open query; if closing either throws SQLException, Kettle wraps it in this KettleDatabaseException. The original query result is lost and the statement resources may be left to GC.

Solutions

  1. Call closeQuery() before closing the Database connection
  2. Inspect the wrapped cause for the underlying SQLException
  3. Treat as cleanup-stage: log and continue if the query results were already consumed
  4. Avoid double-closing by nulling references after close (as the source does)

Example fix

// before
database.disconnect();
database.closeQuery(res); // connection already closed
// after
database.closeQuery(res);
database.disconnect();
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure resources still open before closing
if (res == null || res.isClosed()) return;

Try / catch

try {
  db.closeQuery(res);
} catch (KettleDatabaseException e) {
  log.warn("query cleanup failed (results already consumed): " + e.getCause());
}

Prevention

When it happens

Trigger: SQLException from rs.close() or pstmt.close() — typically because the connection was already closed/aborted before closeQuery was called.

Common situations: Closing the Database/connection before calling closeQuery(), network drop mid-session, or double-close scenarios in pooling drivers.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/8ba3c63f78db5fc5. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:2862

    return fields;
  }

  public void closeQuery( ResultSet res ) throws KettleDatabaseException {
    // close everything involved in the query!
    try {
      if ( res != null ) {
        res.close();
      }
      if ( selStmt != null ) {
        selStmt.close();
        selStmt = null;
      }
      if ( pstmt != null ) {
        pstmt.close();
        pstmt = null;
      }
    } catch ( SQLException ex ) {
      throw new KettleDatabaseException( "Couldn't close query: resultset or prepared statements", ex );
    }
  }

  /**
   * Build the row using ResultSetMetaData rsmd
   *
   * @param rm             The resultset metadata to inquire
   * @param ignoreLength   true if you want to ignore the length (workaround for MySQL bug/problem)
   * @param lazyConversion true if lazy conversion needs to be enabled where possible
   */
  private RowMetaInterface getRowInfo( ResultSetMetaData rm, boolean ignoreLength, boolean lazyConversion )
    throws KettleDatabaseException {
    try {
      log.snap( Metrics.METRIC_DATABASE_GET_ROW_META_START, databaseMeta.getName() );

      if ( rm == null ) {
        throw new KettleDatabaseException( "No result set metadata available to retrieve row metadata!" );
      }

View on GitHub (pinned to f3058517a1)