pentaho/pentaho-kettle · error · KettleDatabaseException
Error executing forEachRow
Error message
Error executing forEachRow
What it means
Database.forEachRow(...) executes a callback for each row of a ResultSet; any exception thrown inside the loop — including from the user-supplied callback itself — is wrapped in this KettleDatabaseException. It can therefore indicate either a fetch failure or a bug in your callback code.
Solutions
- Wrap risky callback logic internally and inspect the chained cause to see if your callback threw
- Null-check row values inside the callback before use
- Validate the expected column layout of the ResultSet before processing
- Catch KettleDatabaseException at the call site and handle per-row failures idempotently so processing can resume
Example fix
// before
db.forEachRow(rs, row -> process(row[5].toString())); // NPE if null
// after
db.forEachRow(rs, row -> { if (row[5] != null) process(row[5].toString()); }); Defensive patterns
Strategy: try-catch
Validate before calling
// make callback total: never throw
db.forEachRow(rs, row -> {
try { process(row); } catch (Exception ex) { log.error("row failed: " + Arrays.toString(row), ex); }
}); Type guard
boolean isUsableRow(Object[] row) { return row != null && row.length > 0; } Try / catch
try {
db.forEachRow(rs, this::processRow);
} catch (KettleDatabaseException e) {
Throwable c = e.getCause();
if (c instanceof RuntimeException) {
throw (RuntimeException) c; // recover your callback's own error
}
throw e; // genuine fetch failure
} Prevention
- Write callbacks that never throw — log and continue on bad rows
- Null-check all accessed columns in the callback
- Keep per-row processing idempotent so restarts are safe
- Unwrap the cause to distinguish callback bugs from fetch failures
When it happens
Trigger: Calling db.forEachRow(rs or sql, callback) where callback.accept(row) throws (NPE, business-logic error) or the underlying row fetch fails; the catch wraps it as 'Error executing forEachRow'.
Common situations: Callback code assuming non-null fields, wrong row shape, or throwing application exceptions that propagate into the Kettle wrapper.
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
- AccessInputMeta.Exception.ErrorSavingToRepository
- An error occurred executing SQL:
- An error occurred executing SQL:
- Cannot fetch driver metadata for
- Couldn't close query: resultset or prepared statements
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/6cf1631d29cd77ab.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:4125
* @param sql The SQL statement to execute
* @param limit The maximum number of rows to process (<=0 means unlimited)
* @param callback The callback to execute for each row (receives Object[] row)
* @throws KettleDatabaseException if something goes wrong
*/
public void forEachRow( String sql, int limit, java.util.function.Consumer<Object[]> callback )
throws KettleDatabaseException {
try ( ResultSet rset = openQuery( sql ) ) {
int count = 0;
while ( rset != null && ( limit <= 0 || count < limit ) ) {
Object[] row = getRow( rset );
if ( row == null ) {
break;
}
callback.accept( row );
count++;
}
} catch ( Exception e ) {
throw new KettleDatabaseException( "Error executing forEachRow", e );
}
}
public List<Object[]> getFirstRows( String tableName, int limit ) throws KettleDatabaseException {
return getFirstRows( tableName, limit, null );
}
/**
* Get the first rows from a table (for preview)
*
* @param tableName The table name (or schema/table combination): this needs to be quoted properly
* @param limit limit <=0 means unlimited, otherwise this specifies the maximum number of rows read.
* @param monitor The progress monitor to update while getting the rows.
* @return An ArrayList of rows.
* @throws KettleDatabaseException in case something goes wrong
*/
public List<Object[]> getFirstRows( String tableName, int limit, ProgressMonitorListener monitor )
throws KettleDatabaseException {View on GitHub (pinned to f3058517a1)