pentaho/pentaho-kettle · error · KettleRowException
BaseStep.SafeMode.Exception.MixingTypes
BaseStep.SafeMode.Exception.MixingTypes
Error message
BaseStep.SafeMode.Exception.MixingTypes
What it means
safeModeChecking compares ValueMetaInterface.getType() positionally; if the Kettle value type (String, Integer, Date, Number, ...) at position i differs between the reference row and the incoming row, KettleRowException is thrown. Field names match but the data types change between rows.
Solutions
- Explicitly declare the field type once and convert values to it before putRow (e.g. always convertNumberToString) instead of deriving type from the Java object.
- Pre-create the output RowMetaInterface in the step's init/processRow and reuse it for every row.
- In table/CSV inputs, set explicit column types in the step dialog rather than relying on inference.
- Add a 'Value Mapper' or 'Select values' metadata tab to force the expected type before the failing step.
Example fix
// before rowMeta.addValueMeta(new ValueMeta(name, data.getClass())); // type varies per row // after rowMeta.addValueMeta(new ValueMeta(name, ValueMetaInterface.TYPE_STRING)); // fixed type
Defensive patterns
Strategy: validation
Validate before calling
for (int i = 0; i < rowMeta.size(); i++) {
if (rowMeta.getValueMeta(i).getType() != referenceMeta.getValueMeta(i).getType())
throw new IllegalStateException("Type mismatch at field " + rowMeta.getValueMeta(i).getName());
} Try / catch
try { putRow(outputRowMeta, row); } catch (KettleRowException e) { if (e.getMessage().contains("MixingTypes")) { logError("Field type changed between rows; coerce values"); } throw e; } Prevention
- Declare output field types explicitly in getFields(), not from data
- Reuse a single prebuilt RowMetaInterface for all rows
- Convert values with valueMeta.convertData before putRow
- Set explicit types in CSV/table input dialogs
When it happens
Trigger: Safe mode enabled; a step emits a field as e.g. ValueMetaInteger on the first row and ValueMetaString on a later row, typically because object class of the value differs and the row meta is rebuilt per row.
Common situations: UDJE/JavaScript steps that sometimes return a String and sometimes a Number for the same field; CSV/table inputs with mixed-type columns and dynamic type inference; a lookup returning null-vs-typed values that rebuild the meta.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- BaseStep.SafeMode.Exception.DoubleFieldnames
- BaseStep.SafeMode.Exception.MixingLayout
- BaseStep.SafeMode.Exception.MixingStorageTypes
- BaseStep.SafeMode.Exception.VaryingSize
- SalesforceUpsert.FieldNotFound
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/8abe4e40f166eea7.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java:2187
//
if ( referenceRowMeta.size() != rowMeta.size() ) {
throw new KettleRowException( BaseMessages.getString( PKG, "BaseStep.SafeMode.Exception.VaryingSize", ""
+ referenceRowMeta.size(), "" + rowMeta.size(), rowMeta.toString() ) );
} else {
// Check field by field for the position of the names...
for ( int i = 0; i < referenceRowMeta.size(); i++ ) {
ValueMetaInterface referenceValue = referenceRowMeta.getValueMeta( i );
ValueMetaInterface compareValue = rowMeta.getValueMeta( i );
if ( !referenceValue.getName().equalsIgnoreCase( compareValue.getName() ) ) {
throw new KettleRowException( BaseMessages.getString(
PKG, "BaseStep.SafeMode.Exception.MixingLayout", "" + ( i + 1 ), referenceValue.getName()
+ " " + referenceValue.toStringMeta(), compareValue.getName()
+ " " + compareValue.toStringMeta() ) );
}
if ( referenceValue.getType() != compareValue.getType() ) {
throw new KettleRowException( BaseMessages.getString( PKG, "BaseStep.SafeMode.Exception.MixingTypes", ""
+ ( i + 1 ), referenceValue.getName() + " " + referenceValue.toStringMeta(), compareValue.getName()
+ " " + compareValue.toStringMeta() ) );
}
if ( referenceValue.getStorageType() != compareValue.getStorageType() ) {
throw new KettleRowException( BaseMessages.getString(
PKG, "BaseStep.SafeMode.Exception.MixingStorageTypes", "" + ( i + 1 ), referenceValue.getName()
+ " " + referenceValue.toStringMeta(), compareValue.getName()
+ " " + compareValue.toStringMeta() ) );
}
}
}
}
/**
* Gets the row from.
*
* @param rowSet the row setView on GitHub (pinned to f3058517a1)