pentaho/pentaho-kettle · error · KettleStepException

GetPreviousRowField.Exception.OutputFieldEmpty

Error message

GetPreviousRowField.Exception.OutputFieldEmpty

What it means

Each configured field in GetPreviousRowField must have a non-empty output (target) field name. During processRow's first-run initialization, an empty output name for any field index throws a KettleStepException with this localized message, including the zero-based field index.

Solutions

  1. Fill in the output field name for every row in the step's fields table
  2. Remove unused/blank field rows from the grid
  3. Re-save the step after editing to persist the corrected names

Example fix

// before (fields grid)
in: amount   out: (empty)
// after
in: amount   out: prev_amount
Defensive patterns

Strategy: validation

Validate before calling

for (int i = 0; i < meta.getFieldOutStream().length; i++) { if (Utils.isEmpty(meta.getFieldOutStream()[i])) { throw new IllegalArgumentException("Output field name empty at index " + i); } }

Prevention

When it happens

Trigger: Executing the transformation with a row in the step's fields grid whose output-field column is blank.

Common situations: Adding a field row but forgetting to type the new field name; importing metadata where out_stream_name was empty; copying step config with partial fields.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at plugins/get-previous-row-field/core/src/main/java/org/pentaho/di/trans/steps/getpreviousrowfield/GetPreviousRowField.java:98

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

      data.inStreamNrs = new int[meta.getFieldInStream().length];
      for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {
        data.inStreamNrs[i] = data.inputRowMeta.indexOfValue( meta.getFieldInStream()[i] );
        if ( data.inStreamNrs[i] < 0 ) { // couldn't find field!

          throw new KettleException( BaseMessages.getString(
            PKG, "GetPreviousRowField.Exception.FieldRequired", meta.getFieldInStream()[i] ) );
        }
      }

      data.outStreamNrs = new String[meta.getFieldInStream().length];
      for ( int i = 0; i < meta.getFieldInStream().length; i++ ) {
        data.outStreamNrs[i] = meta.getFieldOutStream()[i];
        if ( Utils.isEmpty( data.outStreamNrs[i] ) ) {
          throw new KettleStepException( BaseMessages.getString(
            PKG, "GetPreviousRowField.Exception.OutputFieldEmpty", "" + i ) );
        }
      }
    } // end if first

    try {
      Object[] outputRow = getOutputRowData( r );

      putRow( data.outputRowMeta, outputRow ); // copy row to output rowset(s);

      if ( checkFeedback( getLinesRead() ) ) {
        if ( log.isDetailed() ) {
          logDetailed( BaseMessages.getString( PKG, "GetPreviousRowField.Log.LineNumber" ) + getLinesRead() );
        }
      }
    } catch ( KettleException e ) {
      boolean sendToErrorRow = false;
      String errorMessage = null;

View on GitHub (pinned to f3058517a1)