pentaho/pentaho-kettle · error · KettleException
MultiMergeJoinMeta.Exception.UnableToSaveStepInfo
MultiMergeJoinMeta.Exception.UnableToSaveStepInfo
Error message
MultiMergeJoinMeta.Exception.UnableToSaveStepInfo
What it means
Thrown by MultiMergeJoinMeta.saveRep when saving the step's settings to the repository fails, in particular the rep.saveStepAttribute call that persists "join_type". The KettleException message is concatenated with the id_step to identify which step failed to save.
Solutions
- Check the wrapped cause for the underlying SQL/repository error (connectivity, permissions, schema).
- Verify the repository user has write privileges on the step attribute tables and the database is writable.
- Confirm repository connectivity and retry the save after any transient database issue is resolved.
- Check that the repository schema matches your PDI version; run the repository upgrade scripts if needed.
- As a workaround, export the transformation to a .ktr file while the repository write is broken.
Example fix
// before: saving with a read-only repository user rep.save(transMeta); // throws UnableToSaveStepInfo + id_step // after: connect with a user that has INSERT/UPDATE on r_step_attribute Repository rep = new KettleDatabaseRepository(); rep.connect( "repoHost", "8080", "kettle", "kettle", writableUser, writablePass ); rep.save(transMeta);
Defensive patterns
Strategy: try-catch
Validate before calling
// Check write access to the repository before saving
if ( !repository.isActive() || !repUserHasWritePrivileges ) {
throw new IllegalStateException( "Repository not writable for user" );
} Try / catch
try {
repository.save( transMeta );
} catch ( KettleException e ) {
if ( e.getMessage().startsWith( "UnableToSaveStepInfo" ) ) {
// fall back: export to .ktr file, check DB connectivity/permissions, then retry
} else { throw e; }
} Prevention
- Save with a repository account that has INSERT/UPDATE rights on step attribute tables.
- Verify database connectivity before long editing sessions.
- Keep repository schema scripts in sync with the PDI version.
- Periodically export transformations to .ktr as a backup.
When it happens
Trigger: saveRep runs when saving a transformation to a repository; it throws if the repository write fails: dropped database connection, read-only repository/user without write permission, repository schema missing the attribute table/column, transaction rollback, or oversized attribute value.
Common situations: Saving during a transient database outage; a user account with read-only repository rights; repository upgraded/downgraded with a schema mismatch; concurrent edits causing locks or deadlocks on r_step_attribute.
Related errors
- MultiMergeJoinMeta.Exception.UnexpectedErrorReadingStepInfo
- GetTableNamesMeta.Exception.UnableToSaveStepInfo
- GPBulkLoaderMeta.Exception.UnexpectedErrorReadingStepInfoFro…
- GPBulkLoaderMeta.Exception.UnexpectedErrorReadingStepInfoFromRepository
- GPBulkLoaderMeta.Exception.UnableToSaveStepInfoToRepository
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/60da94223eb653dd.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/multimerge/MultiMergeJoinMeta.java:269
rep.saveStepAttribute( id_transformation, id_step, i, "keys", keyFields[i] );
}
String[] inputStepsNames = inputSteps != null ? inputSteps : ArrayUtils.EMPTY_STRING_ARRAY;
rep.saveStepAttribute( id_transformation, id_step, "number_input", inputStepsNames.length );
for ( int i = 0; i < inputStepsNames.length; i++ ) {
rep.saveStepAttribute( id_transformation, id_step, "step" + i, inputStepsNames[ i ] );
}
// The following was the old way of persisting this step to the repository. This was inconsistent with
// how getXML works, and also fails the load/save tester
// List<StreamInterface> infoStreams = getStepIOMeta().getInfoStreams();
// rep.saveStepAttribute( id_transformation, id_step, "number_input", infoStreams.size() );
// for ( int i = 0; i < infoStreams.size(); i++ ) {
// rep.saveStepAttribute( id_transformation, id_step, "step" + i, infoStreams.get( i ).getStepname() );
// }
// inputSteps[i]
rep.saveStepAttribute( id_transformation, id_step, "join_type", getJoinType() );
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString( PKG, "MultiMergeJoinMeta.Exception.UnableToSaveStepInfo" )
+ id_step, e );
}
}
@Override
public void check( List<CheckResultInterface> remarks, TransMeta transMeta, StepMeta stepMeta, RowMetaInterface prev,
String[] input, String[] output, RowMetaInterface info, VariableSpace space, Repository repository,
IMetaStore metaStore ) {
/*
* @todo Need to check for the following: 1) Join type must be one of INNER / LEFT OUTER / RIGHT OUTER / FULL OUTER
* 2) Number of input streams must be two (for now at least) 3) The field names of input streams must be unique
*/
CheckResult cr =
new CheckResult( CheckResultInterface.TYPE_RESULT_WARNING, BaseMessages.getString( PKG,
"MultiMergeJoinMeta.CheckResult.StepNotVerified" ), stepMeta );
remarks.add( cr );
}
View on GitHub (pinned to f3058517a1)