pentaho/pentaho-kettle · error · KettleException

Unable to save step type 'mail' to the repository for…

Error message

Unable to save step type 'mail' to the repository for id_step=

What it means

MailMeta.saveRep() catches KettleDatabaseException while persisting mail step attributes and rethrows as KettleException. Saving the mail step's settings to the repository failed for the given id_step.

Solutions

  1. Read the chained KettleDatabaseException for the root SQL error.
  2. Verify the repository DB user has INSERT/UPDATE rights on the attribute tables and the DB is writable.
  3. Run the repository upgrade tool if the Pentaho version changed and schema columns are missing.
  4. Retry the save after fixing connectivity; alternatively save the transformation to a file as a workaround.
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-save checks
if (rep == null || !rep.isConnected()) throw new KettleException("Repository not connected.");
// Ensure repository metadata is upgraded
if (!rep.getRepositoryMeta().isDefault()) rep.connect("admin", "password");

Try / catch

try { saveToRepo(); } catch (KettleException e) {
  logError("Repository save of mail step failed; export to file instead: " + e.getMessage(), e);
  saveToFile("/backup/mail-step.ktr");
}

Prevention

When it happens

Trigger: saveRep writes attributes and the repository database rejects an INSERT/UPDATE: connection failure, read-only DB, schema constraint violation, or transaction rollback.

Common situations: Repository database disk full or in read-only mode; DB user lacking INSERT privilege on r_step_attribute; repository schema out of date (missing columns after upgrade).

Related errors


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

Appendix: source

Thrown at plugins/mail/impl/src/main/java/org/pentaho/di/trans/steps/mail/MailMeta.java:1105

      rep.saveStepAttribute( id_transformation, id_step, TAG_USE_GRANT_TYPE, grantType );
      rep.saveStepAttribute( id_transformation, id_step, TAG_ONLY_COMMENT, onlySendComment );
      rep.saveStepAttribute( id_transformation, id_step, TAG_USE_HTML, useHTML );
      rep.saveStepAttribute( id_transformation, id_step, TAG_USE_PRIORITY, usePriority );
      rep.saveStepAttribute( id_transformation, id_step, TAG_SECURE_CONNECTION_TYPE, secureConnectionType );

      rep.saveStepAttribute( id_transformation, id_step, TAG_ZIP_FILES, zipFiles );
      rep.saveStepAttribute( id_transformation, id_step, TAG_ZIP_NAME, zipFilename );
      rep.saveStepAttribute( id_transformation, id_step, TAG_ZIP_LIMIT_SIZE, zipLimitSize );

      // save the arguments...
      if ( embeddedImages != null ) {
        for ( int i = 0; i < embeddedImages.length; i++ ) {
          rep.saveStepAttribute( id_transformation, id_step, i, TAG_EMBEDDED_IMAGE, embeddedImages[i] );
          rep.saveStepAttribute( id_transformation, id_step, i, "contentid", contentIds[i] );
        }
      }
    } catch ( KettleDatabaseException dbe ) {
      throw new KettleException( "Unable to save step type 'mail' to the repository for id_step=" + id_step, dbe );
    }
  }

  @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;
    if ( prev == null || prev.isEmpty() ) {
      cr = new CheckResult( CheckResultInterface.TYPE_RESULT_WARNING, BaseMessages.getString(
          PKG, "MailMeta.CheckResult.NotReceivingFields" ), stepMeta );
    } else {
      cr = new CheckResult( CheckResultInterface.TYPE_RESULT_OK, BaseMessages.getString(
          PKG, "MailMeta.CheckResult.StepRecevingData", prev.size() + "" ), stepMeta );
    }
    remarks.add( cr );

    // See if we have input streams leading to this step!

View on GitHub (pinned to f3058517a1)