pentaho/pentaho-kettle · error · KettleValueException

<toString()>: unable to make copy of value type: <getType()>

Error message

<toString()>: unable to make copy of value type: <getType()>

What it means

Thrown by ValueMetaBase.getValue (copy-value path) when the value's data type (getType()) has no case in the copy switch — i.e. Kettle doesn't know how to clone a value of that type. Only TYPE_SERIALIZABLE deliberately bypasses copying; any other unrecognized/non-primitive type hits the default branch.

Solutions

  1. Log/print getType() and getName() on the offending ValueMeta and map the field to a standard type (String/Number/Date/Binary/BigDecimal/Boolean/Integer/Timestamp).
  2. Implement Cloneable/Serializable properly or rely on the TYPE_SERIALIZABLE exemption if the value is a custom object (cloneable).
  3. Align plugin and PDI versions so all type codes in flight are understood by the running core.
  4. Strip or convert custom-typed fields (Select Values → remove/meta-change) before steps that clone rows.

Example fix

// before: custom type code 99 clones fine nowhere
vm.setType(99);
rowMeta.cloneRow(row); // -> "unable to make copy of value type: 99"
// after
vm.setType(ValueMetaInterface.TYPE_STRING); // or mark as serializable
// ValueMetaInterface.TYPE_SERIALIZABLE values are returned as-is without copying
Defensive patterns

Strategy: type-guard

Validate before calling

int t = valueMeta.getType();
if (t != ValueMetaInterface.TYPE_STRING && t != ValueMetaInterface.TYPE_NUMBER
    && t != ValueMetaInterface.TYPE_INTEGER && t != ValueMetaInterface.TYPE_DATE
    && t != ValueMetaInterface.TYPE_BOOLEAN && t != ValueMetaInterface.TYPE_BIGNUMBER
    && t != ValueMetaInterface.TYPE_BINARY && t != ValueMetaInterface.TYPE_TIMESTAMP
    && t != ValueMetaInterface.TYPE_SERIALIZABLE) {
    throw new IllegalStateException("Non-copyable value type: " + t);
}

Type guard

static boolean isCloneableType(ValueMetaInterface vm) {
    switch (vm.getType()) {
        case ValueMetaInterface.TYPE_STRING:
        case ValueMetaInterface.TYPE_NUMBER:
        case ValueMetaInterface.TYPE_INTEGER:
        case ValueMetaInterface.TYPE_DATE:
        case ValueMetaInterface.TYPE_BOOLEAN:
        case ValueMetaInterface.TYPE_BIGNUMBER:
        case ValueMetaInterface.TYPE_BINARY:
        case ValueMetaInterface.TYPE_TIMESTAMP:
        case ValueMetaInterface.TYPE_SERIALIZABLE:
            return true;
        default:
            return false;
    }
}

Try / catch

try {
    Object copy = valueMeta.getValue(original);
} catch (KettleValueException e) {
    throw new IllegalStateException("Field " + valueMeta.getName() + " has unclonable type " + valueMeta.getType(), e);
}

Prevention

When it happens

Trigger: getValue(Object) called during row duplication (RowMeta.cloneRow, step row copying) where getType() returns a type code outside the standard TYPE_* set — custom ValueMeta types, corrupted metadata, or a type added by a newer/older Kettle version than the running one.

Common situations: Mixing Kettle plugin versions where a plugin registers a new data type the core doesn't switch on; deserialized repository metadata with a bad 'value type' integer; passing Kettle rows containing plugin-specific ValueMeta through generic row-cloning code.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/pentaho/di/core/row/value/ValueMetaBase.java:1700

          // inexpensive too.

        case ValueMetaInterface.TYPE_BINARY:
          if ( object instanceof java.lang.String ) {
            return object;
          } else {
            byte[] origin = (byte[]) object;
            byte[] target = new byte[origin.length];
            System.arraycopy( origin, 0, target, 0, origin.length );
            return target;
          }

        case ValueMetaInterface.TYPE_SERIALIZABLE:
          // Let's not create a copy but simply return the same value.
          //
          return object;

        default:
          throw new KettleValueException( toString() + ": unable to make copy of value type: " + getType() );
      }
    } else {

      return object;

    }
  }

  @Override
  public String getCompatibleString( Object object ) throws KettleValueException {
    try {
      String string;

      switch ( type ) {
        case TYPE_DATE:
          switch ( storageType ) {
            case STORAGE_TYPE_NORMAL:
              string = convertDateToCompatibleString( (Date) object );

View on GitHub (pinned to f3058517a1)