pentaho/pentaho-kettle · error · KettleValueException

: Unknown storage type :

Error message

 : Unknown storage type : 

What it means

Inside ValueMetaBase.compare(data1, meta2, data2), when this value has STORAGE_TYPE_INDEXED, it delegates to a nested switch on meta2's storage type; an unrecognized meta2 storage type throws this KettleValueException naming meta2. It signals invalid storage metadata on the right-hand value during cross-storage-type comparison.

Solutions

  1. Fix meta2's storage type to one of STORAGE_TYPE_NORMAL/BINARY_STRING/INDEXED before comparing.
  2. Verify where meta2 metadata originates (which step or XML) and re-generate it with valid constants.
  3. Add a guard comparing meta2.getStorageType() against the valid range (0..2) before calling compare().
  4. If data comes from an older/newer PDI file, re-save it with the runtime version so storage metadata is normalized.

Example fix

// before
int cmp = meta1.compare(data1, meta2, data2); // meta2 storageType invalid

// after
int st = meta2.getStorageType();
if (st < ValueMetaInterface.STORAGE_TYPE_NORMAL || st > ValueMetaInterface.STORAGE_TYPE_INDEXED) {
  meta2.setStorageType(ValueMetaInterface.STORAGE_TYPE_NORMAL);
}
int cmp = meta1.compare(data1, meta2, data2);
Defensive patterns

Strategy: validation

Validate before calling

int st = meta2.getStorageType();
if (st < ValueMetaInterface.STORAGE_TYPE_NORMAL || st > ValueMetaInterface.STORAGE_TYPE_INDEXED) {
  throw new KettleValueException("meta2 has invalid storage type " + st);
}
int cmp = meta1.compare(data1, meta2, data2);

Type guard

boolean isValidStorageType(ValueMetaInterface m) {
  int st = m.getStorageType();
  return st >= ValueMetaInterface.STORAGE_TYPE_NORMAL && st <= ValueMetaInterface.STORAGE_TYPE_INDEXED;
}

Try / catch

try { cmp = meta1.compare(data1, meta2, data2); } catch (KettleValueException e) {
  if (e.getMessage().contains("Unknown storage type")) {
    meta2.setStorageType(ValueMetaInterface.STORAGE_TYPE_NORMAL);
    cmp = meta1.compare(data1, meta2, data2);
  } else throw e;
}

Prevention

When it happens

Trigger: Comparing values where this meta's storageType is STORAGE_TYPE_INDEXED and meta2.getStorageType() is not NORMAL, BINARY_STRING, or INDEXED (i.e. an out-of-range/corrupt integer, typically > 2 or negative).

Common situations: Metadata deserialized from hand-edited or foreign-version XML; programmatic setStorageType() with a wrong constant; indexed values (e.g. from VALUEMAP step) compared against rows built by custom plugins with bogus storage metadata.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

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

              // BACKLOG-18754 - if there is a storage conversion mask, we should use
              // it as the mask for meta2 (meta2 can have specific storage type and type, so
              // it can't be used directly to convert data2 to binary string)
              ValueMetaInterface meta2StorageMask = meta2.clone();
              meta2StorageMask.setConversionMask( storageMetadata.getConversionMask() );
              return compare( data1, meta2StorageMask.convertToBinaryStringStorageType( data2 ) );
            } else {
              return compare( data1, meta2.convertToBinaryStringStorageType( data2 ) );
            }
          case STORAGE_TYPE_INDEXED:
            switch ( meta2.getStorageType() ) {
              case STORAGE_TYPE_INDEXED:
                return compare( data1, data2 ); // not accessible, just to make sure.
              case STORAGE_TYPE_NORMAL:
                return -meta2.compare( data2, convertToNormalStorageType( data1 ) );
              case STORAGE_TYPE_BINARY_STRING:
                return -meta2.compare( data2, convertToBinaryStringStorageType( data1 ) );
              default:
                throw new KettleValueException( meta2.toStringMeta() + " : Unknown storage type : "
                    + meta2.getStorageType() );

            }
          default:
            throw new KettleValueException( toStringMeta() + " : Unknown storage type : " + getStorageType() );
        }
      } else if ( ValueMetaInterface.TYPE_INTEGER == getType() && ValueMetaInterface.TYPE_NUMBER == meta2.getType() ) {
        // BACKLOG-18738
        // compare Double to Integer
        return -meta2.compare( data2, meta2.convertData( this, data1 ) );
      }

      // If the data types are not the same, the first one is the driver...
      // The second data type is converted to the first one.
      //
      return compare( data1, convertData( meta2, data2 ) );
    } catch ( Exception e ) {
      throw new KettleValueException(

View on GitHub (pinned to f3058517a1)