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

  1. 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
  2. Cast or format the measure in the MDX query (CStr/CVal/Format) so it returns a supported type
  3. Adjust the Mondrian schema measure type attribute (e.g. to Numeric/String) so cell values map to supported classes
  4. 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

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


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)