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
- Fix meta2's storage type to one of STORAGE_TYPE_NORMAL/BINARY_STRING/INDEXED before comparing.
- Verify where meta2 metadata originates (which step or XML) and re-generate it with valid constants.
- Add a guard comparing meta2.getStorageType() against the valid range (0..2) before calling compare().
- 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
- Validate storage type range when ingesting metadata from external sources.
- Use only the interface constants, never raw integers, for setStorageType().
- Fix metadata producers (custom steps) that emit unnormalized storage values.
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
- : Comparing values can not be done with data type :
- <toStringMeta()> : Unknown storage type
- : Unable to compare with value []
- : Unknown storage type " + getStorageType()
- : Unknown storage type specified.
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)