pentaho/pentaho-kettle · error · KettleValueException
<toString()> : couldn't convert Number to String
Error message
<toString()> : couldn't convert Number to String
What it means
Thrown by ValueMetaBase's Number-to-String conversion when DecimalFormat.format(number) throws for any reason. It wraps the underlying exception and names the value meta, meaning the numeric value could not be formatted with the current format mask/locale settings.
Solutions
- Check the conversion mask is a valid DecimalFormat pattern for the value
- Handle NaN/Infinity values before conversion (substitute null or a string)
- Normalize the conversion mask so it matches storageMetadata or clear it
- Catch KettleValueException and fall back to String.valueOf(number)
Example fix
// before
valueMeta.setConversionMask("###,##0.00;;"); // invalid pattern
// after
valueMeta.setConversionMask("#,##0.00"); Defensive patterns
Strategy: try-catch
Validate before calling
static boolean isValidDecimalMask(String mask, Locale locale) {
try { new java.text.DecimalFormat(mask, new java.text.DecimalFormatSymbols(locale)); return true; }
catch (IllegalArgumentException e) { return false; }
} Try / catch
try {
String s = valueMeta.getString(numberObject);
} catch (KettleValueException e) {
log.error("Number format failed: " + e.getMessage(), e);
return String.valueOf(numberObject); // fallback
} Prevention
- Test masks with edge values (NaN, Infinity, very large fractions)
- Keep conversion mask consistent between value meta and storageMetadata
- Validate mask syntax with DecimalFormat before applying it
- Avoid exotic masks copied between Number/Integer fields
When it happens
Trigger: Calling getString() on a TYPE_NUMBER value when DecimalFormat.format fails — e.g. a NaN/Infinity value with certain masks, an invalid or incompatible conversion mask, or a broken DecimalFormat created from a bad format string/locale.
Common situations: Conversion masks with illegal characters; formatting Double.NaN or Infinity with a decimal mask; mask mismatch between this value meta and storageMetadata triggering the 50-fraction-digit path; locale changes making the mask invalid.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- <toString()> : couldn't convert Long to String
- <toString()> : couldn't convert String to number with…
- e.toString()
- <toString()> : couldn't convert string
- <toString()> : couldn't convert String to number
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/347a10c3f25744b9.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/row/value/ValueMetaBase.java:999
if ( length < emptyPaddedStrings.length ) {
return emptyPaddedStrings[length];
} else {
return Const.rightPad( "", length );
}
}
}
try {
DecimalFormat format = getDecimalFormat( false );
// When conversion masks are different, we must ensure the number precision is not lost
if ( this.conversionMask != null && storageMetadata != null
&& !this.conversionMask.equals( storageMetadata.getConversionMask() ) ) {
format.setMaximumFractionDigits( 50 );
}
return format.format( number );
} catch ( Exception e ) {
throw new KettleValueException( toString() + " : couldn't convert Number to String ", e );
}
}
protected synchronized String convertNumberToCompatibleString( Double number ) throws KettleValueException {
if ( number == null ) {
return null;
}
return Double.toString( number );
}
protected synchronized Double convertStringToNumber( String string ) throws KettleValueException {
string = Const.trimToType( string, getTrimType() ); // see if trimming needs
// to be performed before
// conversion
if ( Utils.isEmpty( string ) ) {
return null;
}View on GitHub (pinned to f3058517a1)