pentaho/pentaho-kettle · error · KettleException
The result of the filter expression must be a boolean and…
Error message
The result of the filter expression must be a boolean and we got back : {className} What it means
Thrown by the Java Filter step's keep() method when the compiled filter expression evaluates to a non-Boolean value. The filter contract requires the Java expression to return a boolean so rows can be routed to the true/false branches.
Solutions
- Rewrite the filter expression so it evaluates to boolean (use comparisons and logical operators: ==, >, &&, ||).
- Do not use numeric 0/1 flags; use (value == 0) instead.
- Check for accidental casts or method calls returning Object; coerce explicitly, e.g. Boolean.parseBoolean(str).
- Read the className in the message — it names the actual returned type to fix.
Example fix
// before expression: amount & 1 // after expression: (amount & 1) == 1
Defensive patterns
Strategy: type-guard
Validate before calling
// Sanity-check the expression ends in a boolean comparison
String expr = meta.getCondition();
if (!expr.matches(".*(==|!=|>|<|>=|<=|&&|\|\|).*")) {
throw new IllegalStateException("Filter expression must compare/return boolean: " + expr);
} Type guard
boolean isBooleanResult(Object result) { return result instanceof Boolean; } Try / catch
try { boolean keep = calcFields(row); } catch (KettleValueException e) { logError("Filter expression error: " + e.getMessage()); throw e; } Prevention
- Only write boolean expressions in Java Filter (comparisons joined with && / ||).
- Never return numeric flags; convert them: (flag == 1).
- Test the filter with sample data before scheduling.
When it happens
Trigger: data.expressionEvaluator.evaluate(argumentData) returns an object whose class is not Boolean — e.g. the expression ends with an assignment, a comparison wrapped by a method returning Object, or an expression like (a > b) ? 1 : 0 typed as int.
Common situations: Writing an expression whose result is int/String instead of boolean (e.g. using bitwise & instead of &&, or returning a numeric flag); a typo causing the evaluator's generic Object return path; copy-pasting a formula expression from the Formula step into Java Filter.
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.MixingTypes
- DynamicSQLRow.Exception.TemplateReturnDataTypeError
- ElasticSearchBulk.Error.NoJsonFieldFormat
- Function MOD only works with numeric data
- Function NUM2STR only works on Numbers and Integers
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/1a9852fa996bc9fa.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/javafilter/JavaFilter.java:205
// Also create the argument data structure once...
//
data.argumentData = new Object[data.argumentIndexes.size()];
}
// This method can only accept the specified number of values...
//
for ( int x = 0; x < data.argumentIndexes.size(); x++ ) {
int index = data.argumentIndexes.get( x );
ValueMetaInterface outputValueMeta = data.outputRowMeta.getValueMeta( index );
data.argumentData[x] = outputValueMeta.convertToNormalStorageType( r[index] );
}
Object formulaResult = data.expressionEvaluator.evaluate( data.argumentData );
if ( formulaResult instanceof Boolean ) {
return (Boolean) formulaResult;
} else {
throw new KettleException( "The result of the filter expression must be a boolean and we got back : "
+ formulaResult.getClass().getName() );
}
} catch ( Exception e ) {
throw new KettleValueException( e );
}
}
public boolean init( StepMetaInterface smi, StepDataInterface sdi ) {
meta = (JavaFilterMeta) smi;
data = (JavaFilterData) sdi;
if ( super.init( smi, sdi ) ) {
List<StreamInterface> targetStreams = meta.getStepIOMeta().getTargetStreams();
data.trueStepname = targetStreams.get( 0 ).getStepname();
data.falseStepname = targetStreams.get( 1 ).getStepname();
if ( targetStreams.get( 0 ).getStepMeta() != null ^ targetStreams.get( 1 ).getStepMeta() != null ) {
logError( BaseMessages.getString( PKG, "JavaFilter.Log.BothTrueAndFalseNeeded" ) );View on GitHub (pinned to f3058517a1)