pentaho/pentaho-kettle · error · KettleDatabaseException
Unable to close prepared statement pstmt
Error message
Unable to close prepared statement pstmt
What it means
Thrown by Database.getOneRow( String sql ) after successfully fetching a row, when closing the shared prepared statement member pstmt fails. Kettle wraps the driver's exception in a KettleDatabaseException with this message. Like the resultset-close failure, it indicates the JDBC connection or driver is in a bad state, and it happens after the data was read — so it is a resource-release failure, not a query failure.
Solutions
- Inspect the exception cause for the underlying SQLException and address the connection state issue
- Reconnect the Database (disconnect/connect) before further use; consider closing and recreating the Database object entirely
- Upgrade the JDBC driver if close() spuriously throws
- Do not share the Database instance across threads or interleave other operations that would close pstmt while getOneRow runs
Example fix
// before
RowMetaAndData r = database.getOneRow( sql ); // throws "Unable to close prepared statement pstmt"
// after
RowMetaAndData r;
try {
r = database.getOneRow( sql );
} catch ( KettleDatabaseException e ) {
if ( e.getCause() != null ) log.logError( "pstmt 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 a live connection so pstmt close will succeed
} 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( "pstmt" ) ) {
log.logError( "prepared statement cleanup failed", e.getCause() );
database.disconnect();
database.connect();
} else {
throw e;
}
} Prevention
- Check connection health (connection.isClosed()) before running getOneRow
- Never interleave getOneRow with code that closes or replaces the shared pstmt on the same Database object
- Avoid thread-sharing Database instances; each thread gets its own
- Keep the JDBC driver current to avoid spurious close() failures
When it happens
Trigger: Calling db.getOneRow( sql ) where the underlying query used a PreparedStatement stored in the pstmt field (openQuery with parameters), and pstmt.close() threw — typically because the connection was already closed, aborted, or the driver rejected the close call.
Common situations: Connection killed by the server between fetch and cleanup (idle timeouts, failover); shared Database instance whose pstmt was closed/nulled by another code path mid-flight; driver bugs with prepared-statement deallocation; running inside a transaction that was rolled back by another thread.
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
- Couldn't prepare statement:
- Error closing
- Unable to close prepared statement sel_stmt
- Unable to close resultset
- Unable to prepare dimension lookup
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/c4edf0b617a9f99d.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:3619
* @param sql The SQL for the query
* @return one Row with data or null if nothing was found.
*/
public RowMetaAndData getOneRow( String sql ) throws KettleDatabaseException {
ResultSet rs = openQuery( sql );
if ( rs != null ) {
Object[] row = getRow( rs ); // One row only
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 {View on GitHub (pinned to f3058517a1)