pentaho/pentaho-kettle · error · KettleStepException
StringCut.Exception.FieldTypeNotString
Error message
StringCut.Exception.FieldTypeNotString
What it means
StringCut throws this KettleStepException in processRow() when an input field configured for cutting exists in the row but is not of type String. String Cut only operates on String fields; numeric, date, or boolean fields cannot be substring-cut.
Solutions
- Insert a 'Select Values' step before String Cut to convert the field to String
- Change the cut target to a field that is already String
- Adjust the upstream source/query to cast the column to text
- In the step dialog, re-select the field after the type fix
Example fix
// before String Cut on field: amount (Integer) // after Select Values: amount -> String (meta type String, format), then String Cut on amount
Defensive patterns
Strategy: validation
Validate before calling
// validate types before execution
RowMetaInterface input = transMeta.getPrevStepFields(stepMeta);
for (String f : cutMeta.getFieldInStream()) {
int idx = input.indexOfValue(f);
if (idx >= 0 && input.getValueMeta(idx).getType() != ValueMetaInterface.TYPE_STRING) {
throw new IllegalStateException("Field must be String: " + f);
}
} Try / catch
try {
trans.execute(null);
trans.waitUntilFinished();
} catch (KettleException e) {
if (e.getMessage().contains("FieldTypeNotString")) {
// insert a Select Values step converting the field to String, then re-run
}
} Prevention
- Insert a Select Values (type conversion to String) before text-only steps
- Check source schemas after database/table changes
- Preview rows to confirm runtime value types, not just design-time assumptions
- Document expected field types per hop in the transformation
When it happens
Trigger: At the first processed row when getInputRowMeta().getValueMeta(index).getType() != ValueMetaInterface.TYPE_STRING for one of the configured getFieldInStream() fields.
Common situations: Upstream step changed the field type (e.g. source column is Integer); missing a 'Field to string' / Select Values conversion before String Cut; schema drift after changing a database table.
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
- StringOperations.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/f63444b0a5300d23.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/stringcut/StringCut.java:139
if ( first ) {
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.inStreamNrs = new int[meta.getFieldInStream().length];
for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {
data.inStreamNrs[i] = getInputRowMeta().indexOfValue( meta.getFieldInStream()[i] );
if ( data.inStreamNrs[i] < 0 ) {
throw new KettleStepException( BaseMessages.getString( PKG, "StringCut.Exception.FieldRequired", meta
.getFieldInStream()[i] ) );
}
// check field type
if ( getInputRowMeta().getValueMeta( data.inStreamNrs[i] ).getType() != ValueMetaInterface.TYPE_STRING ) {
throw new KettleStepException( BaseMessages.getString(
PKG, "StringCut.Exception.FieldTypeNotString", meta.getFieldInStream()[i] ) );
}
}
data.outStreamNrs = new String[meta.getFieldInStream().length];
for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {
data.outStreamNrs[i] = environmentSubstitute( meta.getFieldOutStream()[i] );
}
data.cutFrom = new int[meta.getFieldInStream().length];
data.cutTo = new int[meta.getFieldInStream().length];
for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {
if ( Utils.isEmpty( environmentSubstitute( meta.getCutFrom()[i] ) ) ) {
data.cutFrom[i] = 0;
} else {
data.cutFrom[i] = Const.toInt( environmentSubstitute( meta.getCutFrom()[i] ), 0 );
}
View on GitHub (pinned to f3058517a1)