pentaho/pentaho-kettle · error · KettleDatabaseException
offending row :
Error message
offending row :
What it means
setValues(PreparedStatement, RowMetaInterface, Object[]) sets each field value on a JDBC PreparedStatement via setValue(); if any field fails to bind, the error is rethrown as KettleDatabaseException('offending row : ' + rowMeta) with the original binding exception as cause. The rowMeta toString in the message identifies the row layout (field names/types) that failed.
Solutions
- Read the cause (KettleDatabaseException / SQLException) to see which bind parameter index failed and why
- Verify row metadata matches actual data types with rowMeta.toString() in the message; fix upstream Select Values / type conversion steps
- Convert problematic values explicitly before insert (e.g. use ValueDataUtil or explicit setValue with correct type)
- Check column lengths and nullability against the data being inserted
- Test the same insert manually via SQL to isolate driver vs data issues
Example fix
// before
database.insertRow(table, rowMeta, rowData);
// after
try {
database.insertRow(table, rowMeta, rowData);
} catch (KettleDatabaseException e) {
throw new KettleDatabaseException("Failed row: " + rowMeta.getString(data, "id"), e);
} Defensive patterns
Strategy: validation
Validate before calling
for (int i = 0; i < rowMeta.size(); i++) {
ValueMetaInterface v = rowMeta.getValueMeta(i);
if (data[i] != null && !v.getNativeDataTypeClass().isInstance(data[i])) {
throw new IllegalStateException("Field " + v.getName() + " expects " + v.getTypeDesc());
}
} Type guard
boolean matchesMeta(ValueMetaInterface v, Object o) {
return o == null || v.getNativeDataTypeClass().isAssignableFrom(o.getClass());
} Try / catch
try {
database.setValues(rowMeta, data, ps);
} catch (KettleDatabaseException e) {
throw new KettleDatabaseException("Bad row id=" + data[0] + ": " + e.getMessage(), e);
} Prevention
- Fix column types explicitly with a Select Values step before writing
- Keep row metadata and target table DDL in sync
- Trim/limit string lengths to column sizes
- Test inserts against the real DB schema in CI
When it happens
Trigger: Calling Database.setValues / insertRow / execStatement value-binding paths where setValue(ps, v, object, i+1) throws KettleDatabaseException — e.g. data object type incompatible with the declared ValueMeta type, nulls in non-nullable contexts, or unsupported value format for the driver.
Common situations: A transformation stream column changed type (String vs Number) upstream; a field contains data too large for the column; passing Kettle values with the wrong storage type after a metadata edit; driver rejects a date/number format.
Related errors
- Error getting the first long value from the max value…
- Unable to get value '" + val.toStringMeta() + "' from…
- Unable to get value '" + val.toStringMeta() + "' from…
- AccessInputMeta.Exception.ErrorSavingToRepository
- An error occurred executing SQL:
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/36fa2833089973cb.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/database/Database.java:1395
v.setPreparedStatementValue( databaseMeta, ps, pos, object );
}
public void setValues( RowMetaAndData row, PreparedStatement ps ) throws KettleDatabaseException {
setValues( row.getRowMeta(), row.getData(), ps );
}
public void setValues( RowMetaInterface rowMeta, Object[] data, PreparedStatement ps )
throws KettleDatabaseException {
// now set the values in the row!
for ( int i = 0; i < rowMeta.size(); i++ ) {
ValueMetaInterface v = rowMeta.getValueMeta( i );
Object object = data[ i ];
try {
setValue( ps, v, object, i + 1 );
} catch ( KettleDatabaseException e ) {
throw new KettleDatabaseException( "offending row : " + rowMeta, e );
}
}
}
/**
* Sets the values of the preparedStatement pstmt.
*
* @param rowMeta
* @param data
*/
public void setValues( RowMetaInterface rowMeta, Object[] data, PreparedStatement ps, int ignoreThisValueIndex )
throws KettleDatabaseException {
// now set the values in the row!
int index = 0;
for ( int i = 0; i < rowMeta.size(); i++ ) {
if ( i != ignoreThisValueIndex ) {
ValueMetaInterface v = rowMeta.getValueMeta( i );
Object object = data[ i ];View on GitHub (pinned to f3058517a1)