pentaho/pentaho-kettle · error · KettleStepException

TableOutput.Exception.FailedToFindField

Error message

TableOutput.Exception.FailedToFindField

What it means

Immediately after the index check, TableOutput.processRow() re-locates each mapped field with searchValueMeta and clones it into the insert row metadata. If the field cannot be found at all (null), it throws KettleStepException with TableOutput.Exception.FailedToFindField. Functionally the same root cause as FieldRequired (missing field in input row), raised on the lookup branch of the same loop.

Solutions

  1. Rebuild the TableOutput field mapping from the live stream ('Get Fields' in the step dialog)
  2. Verify the hop actually carries the expected fields (preview the previous step)
  3. Remove stale entries from the mapping for fields the upstream no longer produces
  4. Ensure the previous step always emits a valid row layout, never a stripped RowMeta

Example fix

// before
data.insertRowMeta.addValueMeta( insertValue ); // throws when insValue == null
// after
if ( getInputRowMeta().searchValueMeta( meta.getFieldStream()[i] ) == null ) {
  throw new KettleStepException( BaseMessages.getString( PKG,
    "TableOutput.Exception.FailedToFindField", meta.getFieldStream()[i] )
    + " — available fields: " + getInputRowMeta().getFieldNames() );
}
data.insertRowMeta.addValueMeta( insertValue );
Defensive patterns

Strategy: validation

Validate before calling

// ensure every database column mapping has a matching stream field before execution
List<String> missing = Arrays.stream( meta.getFieldStream() )
  .filter( f -> prevRowMeta.searchValueMeta( f ) == null )
  .collect( Collectors.toList() );
if ( !missing.isEmpty() ) {
  throw new IllegalStateException( "Fields not found in input stream: " + missing );
}

Type guard

boolean allMappedFieldsPresent( RowMetaInterface rowMeta, TableOutputMeta meta ) {
  return Arrays.stream( meta.getFieldStream() )
    .allMatch( f -> rowMeta.searchValueMeta( f ) != null );
}

Try / catch

try {
  trans.prepareExecution( null );
} catch ( KettleStepException e ) {
  if ( e.getMessage().contains( "TableOutput.Exception.FailedToFindField" ) ) {
    // rebuild the TableOutput field mapping from the incoming stream
  } else { throw e; }
}

Prevention

When it happens

Trigger: processRow() builds data.insertRowMeta on the first row; searchValueMeta(meta.getFieldStream()[i]) returns null because the incoming row's ValueMeta list contains no field with the mapped stream name — empty or misaligned input row metadata, or a mapping configured for a different layout.

Common situations: TableOutput step connected to a hop whose row layout changed (wrong step order, disabled upstream step); mapping copied from another transformation; fields removed by a preceding filter/select step; kettle converting empty rows to empty RowMeta.

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


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/tableoutput/TableOutput.java:115

        // Cache the position of the compare fields in Row row
        //
        data.valuenrs = new int[meta.getFieldDatabase().length];
        for ( int i = 0; i < meta.getFieldDatabase().length; i++ ) {
          data.valuenrs[i] = getInputRowMeta().indexOfValue( meta.getFieldStream()[i] );
          if ( data.valuenrs[i] < 0 ) {
            throw new KettleStepException( BaseMessages.getString(
              PKG, "TableOutput.Exception.FieldRequired", meta.getFieldStream()[i] ) );
          }
        }

        for ( int i = 0; i < meta.getFieldDatabase().length; i++ ) {
          ValueMetaInterface insValue = getInputRowMeta().searchValueMeta( meta.getFieldStream()[i] );
          if ( insValue != null ) {
            ValueMetaInterface insertValue = insValue.clone();
            insertValue.setName( meta.getFieldDatabase()[i] );
            data.insertRowMeta.addValueMeta( insertValue );
          } else {
            throw new KettleStepException( BaseMessages.getString(
              PKG, "TableOutput.Exception.FailedToFindField", meta.getFieldStream()[i] ) );
          }
        }
      }
    }

    try {
      Object[] outputRowData = writeToTable( getInputRowMeta(), r );
      if ( outputRowData != null ) {
        putRow( data.outputRowMeta, outputRowData ); // in case we want it go further...
        incrementLinesOutput();
      }

      if ( checkFeedback( getLinesRead() ) ) {
        if ( log.isBasic() ) {
          logBasic( "linenr " + getLinesRead() );
        }
      }

View on GitHub (pinned to f3058517a1)