pentaho/pentaho-kettle · error · KettleDatabaseException
MondrianInputErrorUnhandledType
MondrianInputErrorUnhandledType
Error message
MondrianInputErrorUnhandledType
What it means
MondrianHelper.createRectangularOutput builds a row layout from an MDX result cell; when a cell value's Java type is not one of the explicitly supported types (String, Number, Date, Boolean, Float, BigDecimal), it throws this KettleDatabaseException. The message embeds valueData.getClass().toString() so the developer can see which type leaked from the Mondrian/olap4j layer. It exists because Kettle ValueMeta types must map 1:1 to concrete Java classes.
Solutions
- Log valueData.getClass() to identify the unhandled type and add/verify it is one of String, Number, Date, Boolean, Float, BigDecimal in the MDX result
- Cast or format the measure in the MDX query (CStr/CVal/Format) so it returns a supported type
- Adjust the Mondrian schema measure type attribute (e.g. to Numeric/String) so cell values map to supported classes
- Align the Mondrian/olap4j driver versions with the PDI plugin version
Example fix
// before WITH MEMBER [Measures].Custom AS [Measures].Sales / [Measures].Count // after (force a supported return type) WITH MEMBER [Measures].Custom AS Format( [Measures].Sales / [Measures].Count, "#,##0.00" )
Defensive patterns
Strategy: try-catch
Validate before calling
// Before configuring the step, probe the MDX result and inspect cell value classes
ResultSet rs = /* execute MDX via olap4j */;
for (int c = 1; c <= rs.getMetaData().getColumnCount(); c++) {
Object v = rs.getObject(c);
if (v != null && !(v instanceof String || v instanceof Number
|| v instanceof java.util.Date || v instanceof Boolean)) {
throw new IllegalStateException("Unhandled cell type at col " + c + ": " + v.getClass());
}
} Type guard
boolean isSupportedCellValue(Object v) {
return v == null || v instanceof String || v instanceof Number
|| v instanceof java.util.Date || v instanceof Boolean;
} Try / catch
try {
meta.getFields(rowMeta, origin, null, null, transMeta, metaStore);
} catch (KettleStepException e) {
// nested KettleDatabaseException message names the offending class
logError("MDX cell type unhandled: " + e.getCause().getMessage(), e);
} Prevention
- Use CStr/CVal/CDate in MDX calculated members to force primitive return types
- Keep Mondrian schema measure types simple (Numeric/String)
- Pin and test Mondrian/olap4j versions against the PDI plugin version
- Preview the step in Spoon before scheduling transformations
When it happens
Trigger: An MDX query returns a cell whose runtime value class is unexpected (e.g. a Mondrian-specific measure wrapper or a custom calculated-member type) and createRectangularOutput's if/else chain falls through to the final else. Invoked from MondrianInputMeta.getFields during layout computation/preview.
Common situations: Calculated members or measures returning exotic objects; Mondrian/olap4j version changes altering returned value classes; schema changes introducing typed measures whose values box differently.
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
- ExcelInput.Exception.InvalidTypeBoolean
- ExcelInput.Exception.InvalidTypeDate
- ExcelInput.Exception.InvalidTypeLabel
- ExcelInput.Exception.InvalidTypeNumber
- GPLoadDataOutput.Exception.TypeNotSupported
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/5f6fb5b0dc66c359.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/mondrianinput/impl/src/main/java/org/pentaho/di/trans/steps/mondrianinput/MondrianHelper.java:302
valueMeta = new ValueMetaInteger( valueName );
valueData = Long.valueOf( ( (Integer) valueData ).longValue() );
} else if ( valueData instanceof Short ) {
valueMeta = new ValueMetaInteger( valueName );
valueData = Long.valueOf( ( (Short) valueData ).longValue() );
} else if ( valueData instanceof Byte ) {
valueMeta = new ValueMetaInteger( valueName );
valueData = Long.valueOf( ( (Byte) valueData ).longValue() );
} else if ( valueData instanceof Long ) {
valueMeta = new ValueMetaInteger( valueName );
} else if ( valueData instanceof Double ) {
valueMeta = new ValueMetaNumber( valueName );
} else if ( valueData instanceof Float ) {
valueMeta = new ValueMetaNumber( valueName );
valueData = Double.valueOf( ( (Float) valueData ).doubleValue() );
} else if ( valueData instanceof BigDecimal ) {
valueMeta = new ValueMetaBigNumber( valueName );
} else {
throw new KettleDatabaseException( BaseMessages.getString( PKG, "MondrianInputErrorUnhandledType", valueData.getClass().toString() ) );
}
valueMetaHash.put( c, valueMeta );
}
if ( valueMetaHash.size() == columnCount ) {
break; // we're done
}
}
// Build the list of valueMetas
List<ValueMetaInterface> valueMetaList = new ArrayList<>();
for ( int c = 0; c < columnCount; c++ ) {
if ( valueMetaHash.containsKey( new Integer( c ) ) ) {
valueMetaList.add( valueMetaHash.get( new Integer( c ) ) );
} else {
// If the entire column is null, assume the missing data as String.View on GitHub (pinned to f3058517a1)