pentaho/pentaho-kettle · error · KettleValueException
Unknown column
Error message
Unknown column '<valueName>'
What it means
getAsJavaType() first locates the field by name in the row's metadata via rowMeta.indexOfValue(). If the field name does not exist in the row (index < 0), it throws this KettleValueException. It prevents null-based misreads when the injected field name doesn't match any row column.
Solutions
- Verify the field name exists in the row (print rowMeta.toStringMeta() or check in Spoon)
- Correct the field name in the injection mapping to match the actual row column
- Ensure upstream steps actually produce/keep the field (it may be removed by a Select Values step)
- Catch KettleValueException and validate field names against rowMeta.getFieldNames() before injection
Example fix
// before
row.getAsJavaType("Amont", String.class, converter); // typo
// after
row.getAsJavaType("Amount", String.class, converter); Defensive patterns
Strategy: validation
Validate before calling
String[] names = row.getRowMeta().getFieldNames();
if (java.util.Arrays.asList(names).indexOf(valueName) < 0) {
throw new IllegalArgumentException("Field '" + valueName + "' not in row: " + String.join(",", names));
} Try / catch
try {
Object v = row.getAsJavaType(valueName, destType, converter);
} catch (KettleValueException e) {
if (e.getMessage().startsWith("Unknown column")) {
log.error("Field " + valueName + " missing; available: " + Arrays.toString(row.getRowMeta().getFieldNames()));
} else throw e;
} Prevention
- Validate field names against rowMeta.getFieldNames() before injection
- Log row layout (rowMeta.toStringMeta()) when debugging injection failures
- Avoid hardcoded field names; drive them from the actual row metadata
- Watch for upstream Select Values steps removing fields
When it happens
Trigger: Calling setProperty/getAsJavaType with a valueName that is not a column in the RowMetaAndData — e.g. a typo in the field name, or the row layout changed upstream and the field was removed/renamed.
Common situations: Metadata injection mapping file listing fields that no longer exist in the source transformation; renamed output fields in a step feeding the injector; case mismatch in field names.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- TransformClassBase.Exception.UnableToFindFieldHelper
- Unable to find ' ' in the row
- Unknown source type:
- ColumnExists.Exception.CouldnotFindField
- CombinationLookup.Exception.FieldNotFound
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/b84672d9c051bb6a.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/RowMetaAndData.java:348
} else if ( boolean.class.isAssignableFrom( destinationType ) ) {
return converter.string2booleanPrimitive( vs );
} else if ( Boolean.class.isAssignableFrom( destinationType ) ) {
return converter.string2boolean( vs );
} else if ( destinationType.isEnum() ) {
return converter.string2enum( destinationType, vs );
} else {
throw new RuntimeException( "Wrong value conversion to " + destinationType );
}
}
/**
* Returns value as specified java type using converter. Used for metadata injection.
*/
public Object getAsJavaType( String valueName, Class<?> destinationType, InjectionTypeConverter converter )
throws KettleValueException {
int idx = rowMeta.indexOfValue( valueName );
if ( idx < 0 ) {
throw new KettleValueException( "Unknown column '" + valueName + "'" );
}
ValueMetaInterface metaType = rowMeta.getValueMeta( idx );
// find by source value type
switch ( metaType.getType() ) {
case ValueMetaInterface.TYPE_STRING:
String vs = rowMeta.getString( data, idx );
return getStringAsJavaType( vs, destinationType, converter );
case ValueMetaInterface.TYPE_BOOLEAN:
Boolean vb = rowMeta.getBoolean( data, idx );
if ( String.class.isAssignableFrom( destinationType ) ) {
return converter.boolean2string( vb );
} else if ( int.class.isAssignableFrom( destinationType ) ) {
return converter.boolean2intPrimitive( vb );
} else if ( Integer.class.isAssignableFrom( destinationType ) ) {
return converter.boolean2integer( vb );
} else if ( long.class.isAssignableFrom( destinationType ) ) {
return converter.boolean2longPrimitive( vb );View on GitHub (pinned to f3058517a1)