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
- Verify the Kettle repository connection is up and writable before saving the transformation
- Open the transformation in Spoon, ensure the Merge Rows step has both reference and compare hops connected, then re-save
- Check repository DB logs/permissions (read-only user, quota) and fix, then retry the save
- 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
- Confirm repository connectivity before batch saves
- Always wire reference and compare hops before saving a Merge Rows step
- Use a repository user with write privileges
- Wrap programmatic saves with retry on transient DB failures
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
- AddSequenceMeta.Exception.UnableToSaveStepInfo
- ColumnExistsMeta.Exception.UnableToSaveStepInfo
- ColumnExistsMeta.Exception.UnexpectedErrorReadingStepInfo
- CreditCardValidatorMeta.Exception.UnableToSaveStepInfo
- CubeInputMeta.Exception.UnableToSaveStepInfo
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)