pentaho/pentaho-kettle · error · KettleValueException

Unknown source type:

Error message

Unknown source type: 

What it means

RowMetaAndData.isEmptyValue() checks whether the value at an index is null for a known Kettle value type. If the row's value meta type is not one of the handled types (String, Number, Integer, Date, Timestamp, InetAddress, Boolean, etc.), it throws this KettleValueException including getTypeDesc(). It guards against silently misinterpreting nullness for unsupported types.

Solutions

  1. Inspect the field's value meta type and convert it to a supported type (e.g. String or Integer) before injecting
  2. Change the step configuration so the injected field uses a standard Kettle value type
  3. Catch KettleValueException and log the offending field name/type
  4. Upgrade Pentaho/Kettle, since newer versions may handle more types

Example fix

// before
rowMeta.setValueMeta(idx, new ValueMetaBinary(field));
// after
rowMeta.setValueMeta(idx, new ValueMetaString(field));
Defensive patterns

Strategy: try-catch

Validate before calling

int idx = row.getRowMeta().indexOfValue(fieldName);
ValueMetaInterface vm = row.getRowMeta().getValueMeta(idx);
switch (vm.getType()) {
  case ValueMetaInterface.TYPE_STRING:
  case ValueMetaInterface.TYPE_NUMBER:
  case ValueMetaInterface.TYPE_INTEGER:
  case ValueMetaInterface.TYPE_BOOLEAN:
  case ValueMetaInterface.TYPE_DATE:
  case ValueMetaInterface.TYPE_TIMESTAMP:
  case ValueMetaInterface.TYPE_INET:
    break; // safe
  default:
    throw new IllegalStateException("Unsupported type for isEmptyValue: " + vm.getTypeDesc());
}

Type guard

boolean isSupportedType(ValueMetaInterface vm) {
  int t = vm.getType();
  return t == ValueMetaInterface.TYPE_STRING || t == ValueMetaInterface.TYPE_NUMBER
    || t == ValueMetaInterface.TYPE_INTEGER || t == ValueMetaInterface.TYPE_BOOLEAN
    || t == ValueMetaInterface.TYPE_DATE || t == ValueMetaInterface.TYPE_TIMESTAMP
    || t == ValueMetaInterface.TYPE_INET;
}

Try / catch

try {
  boolean empty = row.isEmptyValue(idx);
} catch (KettleValueException e) {
  log.error("Unsupported value type for field " + row.getRowMeta().getValueMeta(idx).getTypeDesc(), e);
}

Prevention

When it happens

Trigger: Calling isEmptyValue (directly or via setProperty / createAvroRecord during metadata injection) when the field's ValueMetaInterface type is not covered by the switch, e.g. a Binary, Serializable, or custom value type.

Common situations: Metadata injection where the injected field's type was changed to an unhandled type (e.g. TYPE_BINARY) in a transformation step; custom ValueMeta plugins that add new types not supported by RowMetaAndData.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/9609743f7640798c. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/RowMetaAndData.java:312

      case ValueMetaInterface.TYPE_STRING:
        return rowMeta.getString( data, idx ) == null;
      case ValueMetaInterface.TYPE_BOOLEAN:
        return rowMeta.getBoolean( data, idx ) == null;
      case ValueMetaInterface.TYPE_INTEGER:
        return rowMeta.getInteger( data, idx ) == null;
      case ValueMetaInterface.TYPE_NUMBER:
        return rowMeta.getNumber( data, idx ) == null;
      case ValueMetaInterface.TYPE_BIGNUMBER:
        return rowMeta.getBigNumber( data, idx ) == null;
      case ValueMetaInterface.TYPE_BINARY:
        return rowMeta.getBinary( data, idx ) == null;
      case ValueMetaInterface.TYPE_DATE:
      case ValueMetaInterface.TYPE_TIMESTAMP:
        return rowMeta.getDate( data, idx ) == null;
      case ValueMetaInterface.TYPE_INET:
        return rowMeta.getString( data, idx ) == null;
    }
    throw new KettleValueException( "Unknown source type: " + metaType.getTypeDesc() );
  }

  /**
   * Converts string value into specified type. Used for constant injection.
   */
  public static Object getStringAsJavaType( String vs, Class<?> destinationType, InjectionTypeConverter converter )
    throws KettleValueException {
    if ( String.class.isAssignableFrom( destinationType ) ) {
      return converter.string2string( vs );
    } else if ( int.class.isAssignableFrom( destinationType ) ) {
      return converter.string2intPrimitive( vs );
    } else if ( Integer.class.isAssignableFrom( destinationType ) ) {
      return converter.string2integer( vs );
    } else if ( long.class.isAssignableFrom( destinationType ) ) {
      return converter.string2longPrimitive( vs );
    } else if ( Long.class.isAssignableFrom( destinationType ) ) {
      return converter.string2long( vs );
    } else if ( boolean.class.isAssignableFrom( destinationType ) ) {

View on GitHub (pinned to f3058517a1)