{"record":{"id":"3753fc73a4fd1670","repo":"pentaho/pentaho-kettle","slug":"the-a-b-in-function-only-works-on-numeric-data","errorCode":null,"errorMessage":"The 'A/B in %' function only works on numeric data","messagePattern":"The 'A/B in %' function only works on numeric data","errorType":"exception","errorClass":"KettleValueException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/row/ValueDataUtil.java","lineNumber":982,"sourceCode":"   */\n  @Deprecated\n  public static Object percent1( ValueMetaInterface metaA, Object dataA, ValueMetaInterface metaB, Object dataB ) throws KettleValueException {\n    if ( dataA == null || dataB == null ) {\n      return null;\n    }\n\n    switch ( metaA.getType() ) {\n      case ValueMetaInterface.TYPE_NUMBER:\n        return divideDoubles( multiplyDoubles( 100.0D, metaA.getNumber( dataA ) ), metaB.getNumber( dataB ) );\n      case ValueMetaInterface.TYPE_INTEGER:\n        return divideLongs( multiplyLongs( 100L, metaA.getInteger( dataA ) ), metaB.getInteger( dataB ) );\n      case ValueMetaInterface.TYPE_BIGNUMBER:\n        return divideBigDecimals(\n          multiplyBigDecimals( metaA.getBigNumber( dataA ), new BigDecimal( 100 ), null ), metaB\n            .getBigNumber( dataB ), (MathContext) null );\n\n      default:\n        throw new KettleValueException( \"The 'A/B in %' function only works on numeric data\" );\n    }\n  }\n\n  public static Object percent1( ValueMetaInterface metaA, Object dataA, ValueMetaInterface metaB, Object dataB, VariableSpace space ) throws KettleValueException {\n    if ( dataA == null || dataB == null ) {\n      return null;\n    }\n\n    switch ( metaA.getType() ) {\n      case ValueMetaInterface.TYPE_NUMBER:\n        return divideDoubles( multiplyDoubles( 100.0D, metaA.getNumber( dataA ) ), metaB.getNumber( dataB ) );\n      case ValueMetaInterface.TYPE_INTEGER:\n        return divideLongs( multiplyLongs( 100L, metaA.getInteger( dataA ) ), metaB.getInteger( dataB ) );\n      case ValueMetaInterface.TYPE_BIGNUMBER:\n        return divideBigDecimals(\n          multiplyBigDecimals( metaA.getBigNumber( dataA ), new BigDecimal( 100 ), null ), metaB\n            .getBigNumber( dataB ), space );\n","sourceCodeStart":964,"sourceCodeEnd":1000,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/row/ValueDataUtil.java#L964-L1000","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nValueMetaInterface metaA = new ValueMetaString(\"a\");\nValueMetaInterface metaB = new ValueMetaNumber(\"b\");\nValueDataUtil.divideByteBuffer... // 'A/B in %' call throws\n// after\nValueMetaInterface metaA = new ValueMetaNumber(\"a\");\nObject aNum = ValueDataUtil.convertData(new ValueMetaString(\"a\"), dataA, metaA);\n// then call the percent function with metaA/metaB numeric","handlingStrategy":"type-guard","validationCode":"if (isNumericMeta(metaA) && isNumericMeta(metaB)) {\n  result = /* 'A/B in %' call */;\n} else {\n  // convert both operands to Number via ValueDataUtil.convertData before calling\n}","typeGuard":"boolean isNumericMeta(ValueMetaInterface meta) {\n  if (meta == null) return false;\n  int t = meta.getType();\n  return t == ValueMetaInterface.TYPE_NUMBER\n    || t == ValueMetaInterface.TYPE_INTEGER\n    || t == ValueMetaInterface.TYPE_BIGNUMBER;\n}","tryCatchPattern":"try {\n  result = percentFn(metaA, dataA, metaB, dataB);\n} catch (KettleValueException e) {\n  if (e.getMessage().contains(\"A/B in %\")) {\n    logError(\"Non-numeric operand for 'A/B in %': \" + metaA.getName() + \"/\" + metaB.getName());\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["kettle","pdi","calculator","type-mismatch","percent"],"backgroundTag":"type-mismatch","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}