pentaho/pentaho-kettle · error · KettleStepException
StringOperations.Exception.FieldTypeNotString
Error message
StringOperations.Exception.FieldTypeNotString
What it means
StringOperations throws this KettleStepException in processRow() when a configured input field exists but is not a String (checked via getValueMeta(...).isString()). String Operations (trim, cut, lower/upper, masking, etc.) only support String fields.
Solutions
- Add a 'Select Values' step converting the field to String before String Operations
- Choose a field that is already a String in the step dialog
- Cast the column to text at the source (SQL CAST or Text File input format)
- Re-check the row layout with a preview after the fix
Example fix
// before String Operations: trim on created_at (Date) // after Select Values: created_at -> String (yyyy-MM-dd), then String Operations: trim on created_at
Defensive patterns
Strategy: validation
Validate before calling
RowMetaInterface input = transMeta.getPrevStepFields(stepMeta);
for (String f : sopMeta.getFieldInStream()) {
int idx = input.indexOfValue(f);
if (idx >= 0 && !input.getValueMeta(idx).isString()) {
throw new IllegalStateException("Field must be String: " + f);
}
} Try / catch
try {
trans.execute(null);
trans.waitUntilFinished();
} catch (KettleException e) {
if (e.getMessage().contains("FieldTypeNotString")) {
// add Select Values conversion to String upstream, then re-run
}
} Prevention
- Convert non-String fields to String via Select Values before this step
- Re-verify types after upstream source or query changes
- Preview first rows to confirm runtime types
- Keep a checklist of which steps require String inputs
When it happens
Trigger: On the first processed row when !getInputRowMeta().getValueMeta(data.inStreamNrs[i]).isString() for one of the configured getFieldInStream() fields — e.g. a numeric or Date field was selected.
Common situations: Source column type changed (schema drift); forgetting a 'Select Values' type conversion to String before the step; connecting the step to a stream where the field arrives as Integer/Date.
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
- StringCut.Exception.FieldTypeNotString
- StringCut.Exception.FieldRequired
- StringOperations.Exception.FieldRequired
- AccessInputMeta.Exception.ErrorSavingToRepository
- AccessInputMeta.Exception.FileDoesNotExist
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/2d5a2c2fb857eed9.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/stringoperations/StringOperations.java:239
first = false;
// What's the format of the output row?
data.outputRowMeta = getInputRowMeta().clone();
data.inputFieldsNr = data.outputRowMeta.size();
meta.getFields( getTransMeta().getBowl(), data.outputRowMeta, getStepname(), null, null, this, repository,
metaStore );
data.nrFieldsInStream = meta.getFieldInStream().length;
data.inStreamNrs = new int[data.nrFieldsInStream];
for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {
data.inStreamNrs[i] = getInputRowMeta().indexOfValue( meta.getFieldInStream()[i] );
if ( data.inStreamNrs[i] < 0 ) { // couldn't find field!
throw new KettleStepException( BaseMessages.getString( PKG, "StringOperations.Exception.FieldRequired", meta
.getFieldInStream()[i] ) );
}
// check field type
if ( !getInputRowMeta().getValueMeta( data.inStreamNrs[i] ).isString() ) {
throw new KettleStepException( BaseMessages.getString( PKG, "StringOperations.Exception.FieldTypeNotString",
meta.getFieldInStream()[i] ) );
}
}
data.outStreamNrs = new String[data.nrFieldsInStream];
for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {
data.outStreamNrs[i] = meta.getFieldOutStream()[i];
}
// Keep track of the trim operators locally for a very small
// optimization.
data.trimOperators = new String[data.nrFieldsInStream];
for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {
data.trimOperators[i] = meta.getTrimType()[i];
}
// lower Upper
data.lowerUpperOperators = new String[data.nrFieldsInStream];
for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {View on GitHub (pinned to f3058517a1)