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

  1. Check repository DB connectivity and disk space, then re-save the transformation.
  2. Retry the save after confirming no concurrent writer holds locks on the transformation rows.
  3. Verify the join's lookup hop points to an existing, correctly named step so getLookupStepname() resolves before saving.
  4. 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

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


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)