pentaho/pentaho-kettle · error · KettleValueException

Subtraction can only be done with numbers!

Error message

Subtraction can only be done with numbers!

What it means

This KettleValueException is thrown by Value.minus() when subtraction is attempted on a Value whose type is not numeric (Boolean, String, or any other non-numeric VALUE_TYPE). The legacy compatibility Value class only defines arithmetic for Number, Integer, BigNumber, and Date types; anything else is rejected explicitly.

Solutions

  1. Convert operands to a numeric type first: value.setType( Value.VALUE_TYPE_NUMBER ) after setValue, or use convertString( VALUE_TYPE_NUMBER ).
  2. In transformation design, add a Select Values / Calculator step to set the field type to Integer/Number before subtraction.
  3. Null-check and validate input field metadata (ValueMetaInterface type) before arithmetic.
  4. If the string is a formatted number, parse with a NumberFormat/BigDecimal and store as BigNumber.
  5. Catch KettleValueException around arithmetic to fail fast with a clear field-level message.

Example fix

// before
Value result = strValue.minus( other ); // throws if strValue is STRING
// after
Value num = new Value( "amount", strValue.getNumber() ); // or strValue.convertString( Value.VALUE_TYPE_NUMBER )
Value result = num.minus( other );
Defensive patterns

Strategy: type-guard

Validate before calling

// before subtraction
if ( !( a.isNumber() || a.isInteger() || a.isBigNumber() ) ) {
  a.convertString( Value.VALUE_TYPE_NUMBER );
}

Type guard

boolean isNumericValue( Value v ) {
  return v != null && ( v.isNumber() || v.isInteger() || v.isBigNumber() );
}

Try / catch

try {
  Value result = a.minus( b );
} catch ( KettleValueException e ) {
  throw new IllegalStateException( "Non-numeric operand for minus(): type=" + a.getType(), e );
}

Prevention

When it happens

Trigger: Calling value.minus(other) (or the Kettle formula/calculator step mapping to it) where either operand's VALUE_TYPE is BOOLEAN, STRING, or an unhandled default — e.g. a field read from CSV as String then used directly in a subtraction.

Common situations: Input files where numeric columns were inferred as String; a calculator step wired to a text field; type inference changes after an upstream transformation; forgetting to use the 'Fields > Select/Type' conversion before arithmetic.

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


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/b98d3c344322c71f. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/compatibility/Value.java:2197

  public Value minus( byte v ) throws KettleValueException {
    return minus( new Value( "tmp", (long) v ) );
  }

  public Value minus( Value v ) throws KettleValueException {
    switch ( getType() ) {
      case VALUE_TYPE_BIGNUMBER:
        value.setBigNumber( getBigNumber().subtract( v.getBigNumber() ) );
        break;
      case VALUE_TYPE_NUMBER:
        value.setNumber( getNumber() - v.getNumber() );
        break;
      case VALUE_TYPE_INTEGER:
        value.setInteger( getInteger() - v.getInteger() );
        break;
      case VALUE_TYPE_BOOLEAN:
      case VALUE_TYPE_STRING:
      default:
        throw new KettleValueException( "Subtraction can only be done with numbers!" );
    }
    return this;
  }

  public Value plus( BigDecimal v ) {
    return plus( new Value( "tmp", v ) );
  }

  public Value plus( double v ) {
    return plus( new Value( "tmp", v ) );
  }

  public Value plus( long v ) {
    return plus( new Value( "tmp", v ) );
  }

  public Value plus( int v ) {
    return plus( new Value( "tmp", (long) v ) );

View on GitHub (pinned to f3058517a1)