pentaho/pentaho-kettle · error · KettleDatabaseException

Unable to close prepared statement sel_stmt

Error message

Unable to close prepared statement sel_stmt

What it means

Thrown by Database.getOneRow( String sql ) when closing the select statement held in the selStmt field fails after the row was fetched. The message identifies sel_stmt (the plain Statement used by openQuery for non-parameterized SQL) as the resource that could not be released. It wraps the driver's exception and signals a broken connection or driver-level close failure during statement cleanup.

Solutions

  1. Read the wrapped cause to identify the underlying SQLException and fix the connection problem (timeouts, firewall idle disconnects, etc.)
  2. Reconnect or recreate the Database object before further queries
  3. Upgrade the database's JDBC driver
  4. Give each thread/step its own Database instance to avoid racing on the shared selStmt field

Example fix

// before
RowMetaAndData r = database.getOneRow( sql ); // throws "Unable to close prepared statement sel_stmt"
// after
RowMetaAndData r;
try {
  r = database.getOneRow( sql );
} catch ( KettleDatabaseException e ) {
  log.logError( "sel_stmt close failed", e.getCause() );
  database.disconnect();
  database.connect();
  r = database.getOneRow( sql );
}
Defensive patterns

Strategy: try-catch

Validate before calling

if ( database.getConnection() == null ) {
  database.connect(); // ensure the selStmt close path has a live session
}

Type guard

boolean hasLiveConnection( Database db ) {
  try {
    return db != null && db.getConnection() != null && !db.getConnection().isClosed();
  } catch ( SQLException e ) {
    return false;
  }
}

Try / catch

try {
  RowMetaAndData row = database.getOneRow( sql );
} catch ( KettleDatabaseException e ) {
  if ( e.getMessage() != null && e.getMessage().contains( "sel_stmt" ) ) {
    log.logError( "select statement cleanup failed", e.getCause() );
    database.disconnect();
    database.connect();
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling db.getOneRow( sql ) where openQuery used the selStmt Statement, and selStmt.close() threw — e.g. connection already closed/aborted by the server, driver error on statement close, or the statement was invalidated by concurrent activity on the same Database object.

Common situations: Server-side timeouts or network interruptions that kill the session before cleanup; old/buggy JDBC drivers; sharing one Database instance across steps or threads so cleanup races occur; long-running jobs where the connection went stale between query and close.

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/c1216f695aeb58c9. Report an issue: GitHub.

Appendix: source

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

      try {
        rs.close();
      } catch ( Exception e ) {
        throw new KettleDatabaseException( "Unable to close resultset", e );
      }

      if ( pstmt != null ) {
        try {
          pstmt.close();
        } catch ( Exception e ) {
          throw new KettleDatabaseException( "Unable to close prepared statement pstmt", e );
        }
        pstmt = null;
      }
      if ( selStmt != null ) {
        try {
          selStmt.close();
        } catch ( Exception e ) {
          throw new KettleDatabaseException( "Unable to close prepared statement sel_stmt", e );
        }
        selStmt = null;
      }
      return new RowMetaAndData( rowMeta, row );
    } else {
      throw new KettleDatabaseException( "error opening resultset for query: " + sql );
    }
  }

  public RowMeta getMetaFromRow( Object[] row, ResultSetMetaData md ) throws SQLException, KettleDatabaseException {
    RowMeta meta = new RowMeta();

    for ( int i = 0; i < md.getColumnCount(); i++ ) {
      ValueMetaInterface valueMeta = getValueFromSQLType( md, i + 1, true, false );
      meta.addValueMeta( valueMeta );
    }

    return meta;

View on GitHub (pinned to f3058517a1)