pentaho/pentaho-kettle · error · KettleException

MergeRowsMeta.Exception.UnableToSaveStepInfo

MergeRowsMeta.Exception.UnableToSaveStepInfo

Error message

MergeRowsMeta.Exception.UnableToSaveStepInfo

What it means

MergeRowsMeta.saveRep() persists the Merge Rows step's configuration (reference and compare stream step names) to the Kettle repository. If any exception occurs while saving those step attributes — typically a repository connectivity or persistence failure — it is wrapped in a KettleException with the 'UnableToSaveStepInfo' message plus the step ID.

Solutions

  1. Verify the Kettle repository connection is up and writable before saving the transformation
  2. Open the transformation in Spoon, ensure the Merge Rows step has both reference and compare hops connected, then re-save
  3. Check repository DB logs/permissions (read-only user, quota) and fix, then retry the save
  4. Upgrade/patch Kettle if repository schema version mismatches the engine version

Example fix

// before
rep.saveStepAttribute( id_transformation, id_step, "reference", referenceStream.getStepname() );
// after
// ensure streams are connected first
if ( infoStreams.size() < 2 || infoStreams.get(0).getStepMeta() == null || infoStreams.get(1).getStepMeta() == null ) {
  throw new KettleException( "Merge Rows step must have reference and compare input hops before saving" );
}
rep.saveStepAttribute( id_transformation, id_step, "reference", referenceStream.getStepname() );
Defensive patterns

Strategy: try-catch

Validate before calling

// before saving
if ( transMeta.findStep( "Merge Rows" ) != null ) {
  MergeRowsMeta m = (MergeRowsMeta) transMeta.findStep( "Merge Rows" ).getStepMetaInterface();
  if ( m.getInfoStreams().size() < 2 || m.getInfoStreams().get(0).getStepMeta() == null || m.getInfoStreams().get(1).getStepMeta() == null ) {
    throw new IllegalStateException( "Merge Rows step missing reference/compare input hops" );
  }
}
if ( !repository.isConnected() ) throw new IllegalStateException( "Repository not connected" );

Type guard

function hasConnectedStreams( mergeRowsMeta ) {
  const s = mergeRowsMeta.getInfoStreams();
  return s != null && s.length >= 2 && s[0].getStepMeta() != null && s[1].getStepMeta() != null;
}

Try / catch

try {
  transMeta.saveRep( repository, monitor );
} catch ( KettleException e ) {
  if ( e.getMessage() != null && e.getMessage().contains( "UnableToSaveStepInfo" ) ) {
    // check repository connectivity/permissions, then retry or re-save via Spoon
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling TransMeta.saveRep()/repository save of a transformation containing a Merge Rows step when infoStreams lack expected entries, or the repository write of the 'reference'/'compare' attributes fails (repo down, bad connection, read-only repo).

Common situations: Repository database temporarily unreachable during save; saving a transformation whose Merge Rows step hops were not yet wired so stream info is incomplete; running with a read-only or partially migrated repository.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/mergerows/MergeRowsMeta.java:266

    try {
      for ( int i = 0; i < keyFields.length; i++ ) {
        rep.saveStepAttribute( id_transformation, id_step, i, "key_field", keyFields[i] );
      }

      for ( int i = 0; i < valueFields.length; i++ ) {
        rep.saveStepAttribute( id_transformation, id_step, i, "value_field", valueFields[i] );
      }

      rep.saveStepAttribute( id_transformation, id_step, "flag_field", flagField );

      List<StreamInterface> infoStreams = getStepIOMeta().getInfoStreams();
      StreamInterface referenceStream = infoStreams.get( 0 );
      StreamInterface compareStream = infoStreams.get( 1 );

      rep.saveStepAttribute( id_transformation, id_step, "reference", referenceStream.getStepname() );
      rep.saveStepAttribute( id_transformation, id_step, "compare", compareStream.getStepname() );
    } catch ( Exception e ) {
      throw new KettleException( BaseMessages.getString( PKG, "MergeRowsMeta.Exception.UnableToSaveStepInfo" )
        + id_step, e );
    }
  }

  public boolean chosesTargetSteps() {
    return false;
  }

  public String[] getTargetSteps() {
    return null;
  }

  @Override
  public void getFields( Bowl bowl, RowMetaInterface r, String name, RowMetaInterface[] info, StepMeta nextStep,
    VariableSpace space, Repository repository, IMetaStore metaStore ) throws KettleStepException {
    // We don't have any input fields here in "r" as they are all info fields.
    // So we just merge in the info fields.
    //

View on GitHub (pinned to f3058517a1)