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
- Read the wrapped cause to identify the underlying SQLException and fix the connection problem (timeouts, firewall idle disconnects, etc.)
- Reconnect or recreate the Database object before further queries
- Upgrade the database's JDBC driver
- 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
- Reconnect after idle timeouts so the session survives through statement cleanup
- Inspect e.getCause() for the driver-level reason the close failed
- Do not share a Database object across steps/threads that could invalidate selStmt
- Update JDBC drivers; stale drivers commonly throw during statement close
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
- Error cancelling statement
- Error closing
- Error closing prepared statement
- Unable to close prepared statement pstmt
- Unable to close resultset
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)