pentaho/pentaho-kettle · error · KettleStepException

TableOutput.Exception.FieldRequired

Error message

TableOutput.Exception.FieldRequired

What it means

In TableOutput.processRow(), before writing rows the step caches the index of each configured stream field in the incoming row. If a field named in 'Field to insert' (fieldStream) is not present in the input row (indexOfValue < 0), it throws KettleStepException with TableOutput.Exception.FieldRequired. This is a configuration/data-shape mismatch: the mapping references a field the stream does not deliver.

Solutions

  1. Open the TableOutput step and correct 'Field to insert' mapping to match actual upstream fields
  2. Use 'Get Fields' to rebuild the mapping from the incoming stream
  3. Fix the upstream step (SQL/Select Values/CSV) so it emits the expected field name
  4. Check field-name case and whitespace — matching is exact via indexOfValue

Example fix

// before
String[] fieldStream = meta.getFieldStream(); // contains 'CUST_ID' but stream has 'custid'
// after
String[] fieldStream = Arrays.stream( meta.getFieldStream() )
  .map( f -> getInputRowMeta().searchValueMeta( f ) != null ? f
       : findCaseInsensitive( getInputRowMeta(), f ) )
  .toArray( String[]::new );
Defensive patterns

Strategy: validation

Validate before calling

// validate the mapping against the live input row before executing
Set<String> streamFields = new HashSet<>( Arrays.asList( prevStepFields.getFieldNames() ) );
for ( String f : meta.getFieldStream() ) {
  if ( !streamFields.contains( f ) ) {
    throw new IllegalStateException( "Mapped field missing from input stream: " + f );
  }
}

Type guard

boolean mappingIsValid( RowMetaInterface rowMeta, TableOutputMeta meta ) {
  return Arrays.stream( meta.getFieldStream() )
    .allMatch( f -> rowMeta.indexOfValue( f ) >= 0 );
}

Try / catch

try {
  trans.startExecution();
} catch ( KettleStepException e ) {
  if ( e.getMessage().contains( "TableOutput.Exception.FieldRequired" ) ) {
    // open TableOutput mapping and re-sync with upstream fields
  } else { throw e; }
}

Prevention

When it happens

Trigger: processRow() receives a row whose RowMeta lacks one of the fields listed in the step's field mapping (meta.getFieldStream()[i]), typically on the first row after init; occurs whenever upstream steps are changed after the TableOutput mapping was configured.

Common situations: Renaming or deleting an upstream field without updating TableOutput's mapping; a Select Values step dropping the field; case-sensitive name mismatch between mapping and stream; reusing a saved transformation against a changed source table/query.

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/fef197d9917ed81b. Report an issue: GitHub.

Appendix: source

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

      data.outputRowMeta = getInputRowMeta().clone();
      meta.getFields( getTransMeta().getBowl(), data.outputRowMeta, getStepname(), null, null, this, repository,
        metaStore );

      if ( !meta.specifyFields() ) {
        // Just take the input row
        data.insertRowMeta = getInputRowMeta().clone();
      } else {

        data.insertRowMeta = new RowMeta();

        //
        // 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] ) );
          }
        }
      }
    }

View on GitHub (pinned to f3058517a1)