pentaho/pentaho-kettle · error · KettleStepException

BaseStep.Exception.MetadataDoesntMatchDataRowSize

BaseStep.Exception.MetadataDoesntMatchDataRowSize

Error message

BaseStep.Exception.MetadataDoesntMatchDataRowSize

What it means

In safe mode, BaseStep.handlePutError validates that the row metadata's field count matches the actual data array length before processing an error row. If rowMeta.size() > row.length, a KettleStepException with the localized message 'MetadataDoesntMatchDataRowSize' (including both sizes) is thrown. Safe mode is designed to catch exactly this kind of row/metadata inconsistency at runtime.

Solutions

  1. Fix the emitting step so each row's data array has exactly rowMeta.size() values.
  2. Update row metadata (RowMetaInterface) to match the actual fields produced, or vice versa.
  3. Run once without safe mode only if you accept weaker validation — better to fix the producing step.
  4. Catch KettleStepException, parse the metadata vs data sizes in the message, and compare against the failing step's field definitions.

Example fix

// before
RowMetaInterface meta = buildMeta(); // 5 fields
Object[] row = new Object[3]; // short row
putRow(meta, row);

// after
Object[] row = new Object[meta.size()]; // fill all 5 fields
putRow(meta, row);
Defensive patterns

Strategy: validation

Validate before calling

// Validate row length matches metadata before putRow (safe mode invariant)
if (rowMeta.size() > row.length) {
  throw new IllegalStateException(
    "metadata=" + rowMeta.size() + " data=" + row.length);
}

Type guard

boolean matchesMetadata(RowMetaInterface meta, Object[] row) {
  return row != null && row.length == meta.size();
}

Try / catch

try {
  putRow(rowMeta, row);
} catch (KettleStepException e) {
  if (e.getMessage().contains("MetadataDoesntMatchDataRowSize")) {
    logError("Row/metadata size mismatch: " + e.getMessage(), e);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Transformation run with safe mode enabled while handlePutError receives a row whose Object[] data is shorter than the declared RowMetaInterface field count — typically a step emitted rows without filling all declared fields.

Common situations: Custom/plugin steps that declare more fields than they produce; 'Add constants'/'User defined Java class' output rows built incorrectly; metadata changed upstream (added fields) but code paths not updated; safe mode deliberately enabled to detect such bugs.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — 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/edcb2aa5111b5e20. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/step/BaseStep.java:1679

   * @param rowMeta           the row meta
   * @param row               the row
   * @param nrErrors          the nr errors
   * @param errorDescriptions the error descriptions
   * @param fieldNames        the field names
   * @param errorCodes        the error codes
   * @throws KettleStepException the kettle step exception
   */
  public void putError( RowMetaInterface rowMeta, Object[] row, long nrErrors, String errorDescriptions,
                        String fieldNames, String errorCodes ) throws KettleStepException {
    getRowHandler().putError( rowMeta, row, nrErrors, errorDescriptions, fieldNames, errorCodes );
  }


  private void handlePutError( RowMetaInterface rowMeta, Object[] row, long nrErrors, String errorDescriptions,
                               String fieldNames, String errorCodes ) throws KettleStepException {
    if ( trans.isSafeModeEnabled() ) {
      if ( rowMeta.size() > row.length ) {
        throw new KettleStepException( BaseMessages.getString(
          PKG, "BaseStep.Exception.MetadataDoesntMatchDataRowSize", Integer.toString( rowMeta.size() ), Integer
            .toString( row != null ? row.length : 0 ) ) );
      }
    }

    StepErrorMeta stepErrorMeta = stepMeta.getStepErrorMeta();

    if ( errorRowMeta == null ) {
      errorRowMeta = rowMeta.clone();

      RowMetaInterface add = stepErrorMeta.getErrorRowMeta( nrErrors, errorDescriptions, fieldNames, errorCodes );
      errorRowMeta.addRowMeta( add );
    }

    Object[] errorRowData = RowDataUtil.allocateRowData( errorRowMeta.size() );
    if ( row != null ) {
      System.arraycopy( row, 0, errorRowData, 0, rowMeta.size() );
    }

View on GitHub (pinned to f3058517a1)