pentaho/pentaho-kettle · error · KettleException
JoinRowsMeta.Exception.UnableToSaveStepInfoToRepository
JoinRowsMeta.Exception.UnableToSaveStepInfoToRepository
Error message
JoinRowsMeta.Exception.UnableToSaveStepInfoToRepository
What it means
JoinRowsMeta.saveRep() throws this KettleException when saving the Join Rows step attributes to a repository fails, including saving the main step name and the condition via rep.saveConditionStepAttribute. The message is concatenated with id_step to help locate the offending step. It means persistence of the step definition to the repository failed and the transformation definition is not (fully) saved.
Solutions
- Check repository DB connectivity and disk space, then re-save the transformation.
- Retry the save after confirming no concurrent writer holds locks on the transformation rows.
- Verify the join's lookup hop points to an existing, correctly named step so getLookupStepname() resolves before saving.
- Export the transformation to .ktr as a workaround to preserve work, then fix repository access and re-save.
Example fix
// before
repository.save( transMeta, "join transform", null, true ); // saveRep throws on flaky DB
// after ( connectivity check + retry )
if ( !repository.isConnected() ) repository.connect( "prod_rep" );
int attempts = 0;
while ( true ) {
try { repository.save( transMeta, "join transform", null, true ); break; }
catch ( KettleException e ) {
if ( ++attempts >= 3 ) { transMeta.exportToFile( "backup.ktr" ); throw e; }
Thread.sleep( 1000L * attempts );
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if ( !repository.isConnected() || new File( "/" ).getUsableSpace() == 0 ) {
throw new IllegalStateException( "Repository unavailable or disk full before save" );
} Try / catch
try {
repository.save( transMeta, versionComment, null, true );
} catch ( KettleException e ) {
if ( e.getMessage() != null && e.getMessage().contains( "UnableToSaveStepInfoToRepository" ) ) {
transMeta.exportToFile( "unsaved-backup.ktr" ); // preserve work before aborting
throw new IllegalStateException( "Repository save failed; work exported to unsaved-backup.ktr", e );
}
throw e;
} Prevention
- Avoid two developers saving the same transformation concurrently; use version comments and lock discipline.
- Monitor repository DB health and free space before large save operations.
- Resolve join lookup hops (no dangling/renamed main or lookup steps) before saving.
- Export to .ktr periodically so a failed repository save never loses work.
When it happens
Trigger: saveRep called during transformation save to a repository; fails when saveStepAttribute or saveConditionStepAttribute throws due to a lost DB connection, transaction/lock timeout, or the referenced lookup step (getLookupStepname()) resolving issues just before attribute writes.
Common situations: Repository database down or read-only during save; concurrent saves by two developers causing lock contention; repository quota/disk-full on the DB server; condition referencing a hop/step that was renamed so the saved step name is stale.
Related errors
- ERROR_0003_Cannot_Save_Job_Entry
- Error saving job
- GetSequenceMeta.Exception.UnableToSaveStepInfo
- GroupByMeta.Exception.UnableToSaveStepInfoToRepository
- JobEntryWaitForSQL.UnableSaveRep
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/adb8f420e6b10b33.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/trans/steps/joinrows/JoinRowsMeta.java:274
PKG, "JoinRowsMeta.Exception.UnexpectedErrorInReadStepInfoFromRepository" ), e );
}
}
@Override
public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_transformation, ObjectId id_step ) throws KettleException {
try {
rep.saveStepAttribute( id_transformation, id_step, "directory", directory );
rep.saveStepAttribute( id_transformation, id_step, "prefix", prefix );
rep.saveStepAttribute( id_transformation, id_step, "cache_size", cacheSize );
if ( mainStepname == null ) {
mainStepname = getLookupStepname();
}
rep.saveStepAttribute( id_transformation, id_step, "main", mainStepname );
rep.saveConditionStepAttribute( id_transformation, id_step, "id_condition", condition );
} catch ( Exception e ) {
throw new KettleException( BaseMessages.getString(
PKG, "JoinRowsMeta.Exception.UnableToSaveStepInfoToRepository" )
+ id_step, e );
}
}
@Override
public void getFields( Bowl bowl, RowMetaInterface rowMeta, String origin, RowMetaInterface[] info, StepMeta nextStep,
VariableSpace space, Repository repository, IMetaStore metaStore ) throws KettleStepException {
if ( space instanceof TransMeta ) {
TransMeta transMeta = (TransMeta) space;
StepMeta[] steps = transMeta.getPrevSteps( transMeta.findStep( origin ) );
StepMeta mainStep = transMeta.findStep( getMainStepname() );
rowMeta.clear();
if ( mainStep != null ) {
rowMeta.addRowMeta( transMeta.getStepFields( mainStep ) );
}
for ( StepMeta step : steps ) {
if ( mainStep == null || !step.equals( mainStep ) ) {View on GitHub (pinned to f3058517a1)