pentaho/pentaho-kettle · error · KettleDatabaseException
Couldn't prepare statement:
Error message
Couldn't prepare statement:
What it means
KettleDatabaseException thrown when Connection.prepareStatement(sql) fails, wrapping the SQLException and including the offending SQL in the message. Means the driver rejected the SQL at prepare time — typically syntax errors, unknown tables/columns, or a closed connection.
Solutions
- Read the SQL printed in the message and run it manually in the DB to see the precise syntax error
- Verify the table/column names and schema exist and are correctly quoted/cased
- Confirm the connection is still open; reconnect if it was closed
- Adapt SQL to the target database dialect
Example fix
// before String sql = "INSERT INTO usr (id,name) VALUES (?, ?)"; // table is actually 'users' database.prepareInsert(rowMeta, schema, "usr"); // after String sql = "INSERT INTO users (id,name) VALUES (?, ?)"; database.prepareInsert(rowMeta, schema, "users");
Defensive patterns
Strategy: try-catch
Validate before calling
if ( database.getConnection() == null || database.getConnection().isClosed() ) {
database.connect();
} Type guard
boolean canPrepare( Database db ) throws SQLException {
Connection c = db.getConnection();
return c != null && !c.isClosed();
} Try / catch
try {
database.prepareInsert( rowMeta, schema, table );
} catch ( KettleDatabaseException e ) {
log.error( "Prepare failed for SQL: " + e.getMessage() );
throw e;
} Prevention
- Test generated SQL directly in the target DB
- Validate table/column names and quoting per dialect
- Reconnect on stale connections before preparing statements
- Keep dynamic SQL building covered by unit tests against the real dialect
When it happens
Trigger: Calling prepareSQL/prepareInsert/lookup paths where connection.prepareStatement() throws SQLException — invalid SQL syntax, referenced table/column does not exist, connection closed, or parameter count unsupported.
Common situations: Typo in table/column names, SQL built dynamically with wrong placeholders, missing schema, DB dialect differences (SQL valid in one engine, not another), or stale closed connection.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- Unable to prepare dimension lookup
- An error occurred executing SQL:
- Couldn't execute SQL:
- Couldn't find any rows because of an error :
- Couldn't get a result because of an error :
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/5b00659f8b623ecd.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:1269
* Prepare a statement to be executed on the database.
*
* @param sql The SQL to be prepared
* @param returnKeys set to true if you want to return generated keys from an insert statement
* @return The PreparedStatement object.
* @throws KettleDatabaseException
*/
public PreparedStatement prepareSQL( String sql, boolean returnKeys ) throws KettleDatabaseException {
DatabaseInterface databaseInterface = databaseMeta.getDatabaseInterface();
boolean supportsAutoGeneratedKeys = databaseInterface.supportsAutoGeneratedKeys();
try {
if ( returnKeys && supportsAutoGeneratedKeys ) {
return connection.prepareStatement( databaseMeta.stripCR( sql ), Statement.RETURN_GENERATED_KEYS );
} else {
return connection.prepareStatement( databaseMeta.stripCR( sql ) );
}
} catch ( SQLException ex ) {
throw new KettleDatabaseException( "Couldn't prepare statement:" + Const.CR + sql, ex );
}
}
public void closeLookup() throws KettleDatabaseException {
if ( pstmt != null ) {
closePreparedStatement( pstmt );
pstmt = null;
}
}
public void closePreparedStatement( PreparedStatement ps ) throws KettleDatabaseException {
if ( ps != null ) {
try {
ps.close();
} catch ( SQLException e ) {
throw new KettleDatabaseException( "Error closing prepared statement", e );
}
}View on GitHub (pinned to f3058517a1)