pentaho/pentaho-kettle · error · KettleStepException

StreamLookup.Exception.UnableToFindField

Error message

StreamLookup.Exception.UnableToFindField

What it means

StreamLookup throws this while reading the lookup stream when a configured key lookup field cannot be found in the incoming lookup row metadata. indexOfValue() returns -1, meaning the field name in the step's 'key lookup' setting does not exist in the source (lookup) stream. It aborts the step with KettleStepException naming the missing field.

Solutions

  1. Open the StreamLookup step dialog and re-select the key lookup fields so they match fields actually present on the lookup (info/source) input stream
  2. Fix the upstream step so it emits the expected key field (check Rename Field/Delete/Select Values steps)
  3. Re-hop the correct stream to the lookup input of the StreamLookup step
  4. Edit the transformation XML/ktr to correct the keylookup field name typo

Example fix

// before (transformation XML)
<key_lookup>cust_id</key_lookup>
// after (match actual upstream field)
<key_lookup>customerID</key_lookup>
Defensive patterns

Strategy: validation

Validate before calling

// Before running the transformation, validate keys exist on the lookup stream:
for (String key : meta.getKeylookup()) {
  if (lookupRowMeta.indexOfValue(key) < 0)
    throw new IllegalStateException("Lookup stream missing key field: " + key);
}

Type guard

boolean lookupHasField(RowMetaInterface rowMeta, String field) {
  return rowMeta != null && rowMeta.indexOfValue(field) >= 0;
}

Try / catch

try {
  step.processRow();
} catch (KettleStepException e) {
  if (e.getMessage().contains("UnableToFindField")) { /* reconfigure field mapping */ }
  throw e;
}

Prevention

When it happens

Trigger: readLookupValues (via processRow) calls rowSet.getRowMeta().indexOfValue(meta.getKeylookup()[i]) and gets -1 because a key field in the step metadata is absent from the lookup stream's row structure.

Common situations: Upstream step was renamed/deleted a field after the StreamLookup step was configured; hop wiring changed so a different stream feeds the lookup input; typo in field name in transformation XML; transformation copied between environments with different upstream logic.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/streamlookup/StreamLookup.java:167

    while ( rowData != null ) {
      if ( log.isRowLevel() ) {
        logRowlevel( BaseMessages.getString( PKG, "StreamLookup.Log.ReadLookupRow" )
          + rowSet.getRowMeta().getString( rowData ) );
      }

      if ( firstRun ) {
        firstRun = false;
        data.hasLookupRows = true;

        data.infoMeta = rowSet.getRowMeta().clone();
        RowMetaInterface cacheKeyMeta = new RowMeta();
        RowMetaInterface cacheValueMeta = new RowMeta();

   // Look up the keys in the source rows
        for ( int i = 0; i < meta.getKeylookup().length; i++ ) {
          keyNrs[i] = rowSet.getRowMeta().indexOfValue( meta.getKeylookup()[i] );
          if ( keyNrs[i] < 0 ) {
            throw new KettleStepException( BaseMessages.getString(
              PKG, "StreamLookup.Exception.UnableToFindField", meta.getKeylookup()[i] ) );
          }
          cacheKeyMeta.addValueMeta( rowSet.getRowMeta().getValueMeta( keyNrs[i] ) );
        }
       // Save the data types of the keys to optionally convert input rows later on...
        if ( data.keyTypes == null ) {
          data.keyTypes = cacheKeyMeta.clone();
        }

        // Cache keys are stored as normal types, not binary
        for ( int i = 0; i < keyNrs.length; i++ ) {
          cacheKeyMeta.getValueMeta( i ).setStorageType( ValueMetaInterface.STORAGE_TYPE_NORMAL );
        }

       for ( int v = 0; v < meta.getValue().length; v++ ) {
          valueNrs[v] = rowSet.getRowMeta().indexOfValue( meta.getValue()[v] );
          if ( valueNrs[v] < 0 ) {
            throw new KettleStepException( BaseMessages.getString(

View on GitHub (pinned to f3058517a1)