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

  1. Read the cause (KettleDatabaseException / SQLException) to see which bind parameter index failed and why
  2. Verify row metadata matches actual data types with rowMeta.toString() in the message; fix upstream Select Values / type conversion steps
  3. Convert problematic values explicitly before insert (e.g. use ValueDataUtil or explicit setValue with correct type)
  4. Check column lengths and nullability against the data being inserted
  5. 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

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


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)