pentaho/pentaho-kettle · error · KettleException

SSHMeta.Exception.UnableToSaveStepInfo

Error message

SSHMeta.Exception.UnableToSaveStepInfo

What it means

SSHMeta.Exception.UnableToSaveStepInfo is thrown when persisting SSH step settings to a repository (saveRep). Any failure saving a step attribute (or encrypting the proxy password) is wrapped in a KettleException with this message plus the step id. It means the transformation could not be saved with current settings.

Solutions

  1. Check repository connectivity and that it is not read-only
  2. Confirm the repository user has write permissions on transformation tables
  3. Upgrade the repository schema (r_ tables) to match the Pentaho version
  4. Retry the save after fixing the wrapped cause exception
Defensive patterns

Strategy: try-catch

Validate before calling

if (rep == null || !rep.isConnected()) {
  throw new IllegalStateException("Repository not connected before save");
}

Try / catch

try {
  transMeta.save(rep, "comment");
} catch (KettleException e) {
  logError("Save failed for step " + e.getMessage() + ": " + e.getCause());
  exportToXmlAsFallback();
}

Prevention

When it happens

Trigger: Repository insert/update failing during saveStepAttribute (connection loss, constraint violation, permissions), or Encr.encryptPasswordIfNotUsingVariables throwing on bad input.

Common situations: Repository database down or read-only; user lacks write permission; repository schema out of date; network interruption during save.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/c894a987040829a1. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/ssh/SSHMeta.java:486

      rep.saveStepAttribute( idTransformation, idStep, ATTR_USER_NAME, userName );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_PASSWORD, Encr
        .encryptPasswordIfNotUsingVariables( password ) );

      rep.saveStepAttribute( idTransformation, idStep, ATTR_USE_PRIVATE_KEY, usePrivateKey );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_KEY_FILE_NAME, keyFileName );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_PASS_PHRASE, Encr
        .encryptPasswordIfNotUsingVariables( passPhrase ) );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_STD_OUT_FIELD_NAME, stdOutFieldName );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_STD_ERR_FIELD_NAME, stdErrFieldName );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_TIME_OUT, timeOut );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_PROXY_HOST, proxyHost );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_PROXY_PORT, proxyPort );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_PROXY_USERNAME, proxyUsername );
      rep.saveStepAttribute( idTransformation, idStep, ATTR_PROXY_PASSWORD, Encr
        .encryptPasswordIfNotUsingVariables( proxyPassword ) );

    } catch ( Exception e ) {
      throw new KettleException(
        BaseMessages.getString( PKG, "SSHMeta.Exception.UnableToSaveStepInfo" ) + idStep, 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 ) {

    CheckResult cr;
    String errorMessage = "";

    // Target hostname
    if ( Utils.isEmpty( getServerName() ) ) {
      errorMessage = BaseMessages.getString( PKG, "SSHMeta.CheckResult.TargetHostMissing" );
      cr = new CheckResult( CheckResultInterface.TYPE_RESULT_ERROR, errorMessage, stepMeta );
      remarks.add( cr );
    } else {

View on GitHub (pinned to f3058517a1)