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

  1. Check the wrapped cause for the underlying SQL/repository error (connectivity, permissions, schema).
  2. Verify the repository user has write privileges on the step attribute tables and the database is writable.
  3. Confirm repository connectivity and retry the save after any transient database issue is resolved.
  4. Check that the repository schema matches your PDI version; run the repository upgrade scripts if needed.
  5. 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

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


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)