pentaho/pentaho-kettle · error · KettleValueException
The 'A/B in %' function only works on numeric data
Error message
The 'A/B in %' function only works on numeric data
What it means
ValueDataUtil.divideBytes... specifically the percentOfTotal-style helper computing (A/B)*100 implements only the numeric types; any non-numeric pair reaches the default branch and throws KettleValueException. It means A or B (or both) given to the 'A/B in %' operation is not a Number/Integer/BigNumber.
Solutions
- Convert both fields to numeric types (Select values step: String -> Number) before the Calculator step
- Fix the source step's column type definitions (Text/Excel input) so A and B are read as numbers
- Verify the Calculator field mappings for the 'A/B in %' operation reference the intended numeric fields
- Null-check/type-check rows before the calculation with a 'Filter rows' or 'Java Script' step
Example fix
// before
ValueMetaInterface metaA = new ValueMetaString("a");
ValueMetaInterface metaB = new ValueMetaNumber("b");
ValueDataUtil.divideByteBuffer... // 'A/B in %' call throws
// after
ValueMetaInterface metaA = new ValueMetaNumber("a");
Object aNum = ValueDataUtil.convertData(new ValueMetaString("a"), dataA, metaA);
// then call the percent function with metaA/metaB numeric Defensive patterns
Strategy: type-guard
Validate before calling
if (isNumericMeta(metaA) && isNumericMeta(metaB)) {
result = /* 'A/B in %' call */;
} else {
// convert both operands to Number via ValueDataUtil.convertData before calling
} Type guard
boolean isNumericMeta(ValueMetaInterface meta) {
if (meta == null) return false;
int t = meta.getType();
return t == ValueMetaInterface.TYPE_NUMBER
|| t == ValueMetaInterface.TYPE_INTEGER
|| t == ValueMetaInterface.TYPE_BIGNUMBER;
} Try / catch
try {
result = percentFn(metaA, dataA, metaB, dataB);
} catch (KettleValueException e) {
if (e.getMessage().contains("A/B in %")) {
logError("Non-numeric operand for 'A/B in %': " + metaA.getName() + "/" + metaB.getName());
}
throw e;
} Prevention
- Verify both fields in the Calculator 'A/B in %' line are numeric-typed
- Convert percent/denominator fields from string at the input step, not at calculation time
- Also null-guard B: even with numeric types, division by zero must be handled separately
- Pin transformation metadata with tests that assert row value meta types
When it happens
Trigger: Calling the 'A/B in %' calculator function (ValueDataUtil.percent... with MathContext null path) where metaA or metaB type is e.g. String, Date, or Boolean.
Common situations: String-typed columns from CSV/Excel inputs used in a Calculator percent computation, forgetting a type conversion step, field reordering in 'Select values' swapping in a string field, schema drift after upstream changes.
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
- The 'A-B%' function only works on numeric data
- The 'A+B%' function only works on numeric data
- The 'sqrt' function only works on numeric data.
- Calculator.Error.NoNameField
- Calculator.Error.UnableFindField
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/3753fc73a4fd1670.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/row/ValueDataUtil.java:982
*/
@Deprecated
public static Object percent1( ValueMetaInterface metaA, Object dataA, ValueMetaInterface metaB, Object dataB ) throws KettleValueException {
if ( dataA == null || dataB == null ) {
return null;
}
switch ( metaA.getType() ) {
case ValueMetaInterface.TYPE_NUMBER:
return divideDoubles( multiplyDoubles( 100.0D, metaA.getNumber( dataA ) ), metaB.getNumber( dataB ) );
case ValueMetaInterface.TYPE_INTEGER:
return divideLongs( multiplyLongs( 100L, metaA.getInteger( dataA ) ), metaB.getInteger( dataB ) );
case ValueMetaInterface.TYPE_BIGNUMBER:
return divideBigDecimals(
multiplyBigDecimals( metaA.getBigNumber( dataA ), new BigDecimal( 100 ), null ), metaB
.getBigNumber( dataB ), (MathContext) null );
default:
throw new KettleValueException( "The 'A/B in %' function only works on numeric data" );
}
}
public static Object percent1( ValueMetaInterface metaA, Object dataA, ValueMetaInterface metaB, Object dataB, VariableSpace space ) throws KettleValueException {
if ( dataA == null || dataB == null ) {
return null;
}
switch ( metaA.getType() ) {
case ValueMetaInterface.TYPE_NUMBER:
return divideDoubles( multiplyDoubles( 100.0D, metaA.getNumber( dataA ) ), metaB.getNumber( dataB ) );
case ValueMetaInterface.TYPE_INTEGER:
return divideLongs( multiplyLongs( 100L, metaA.getInteger( dataA ) ), metaB.getInteger( dataB ) );
case ValueMetaInterface.TYPE_BIGNUMBER:
return divideBigDecimals(
multiplyBigDecimals( metaA.getBigNumber( dataA ), new BigDecimal( 100 ), null ), metaB
.getBigNumber( dataB ), space );
View on GitHub (pinned to f3058517a1)