pentaho/pentaho-kettle · error · KettleException

JobEntryMailValidator.Meta.UnableToSaveToRep

Error message

JobEntryMailValidator.Meta.UnableToSaveToRep

What it means

JobEntryMailValidator.saveRep() throws this KettleException when writing the job entry's attributes to the Kettle repository fails with a KettleDatabaseException. The message key is concatenated with the job id for identification. The original database exception is attached as the cause.

Solutions

  1. Inspect getCause() (KettleDatabaseException) to find the exact SQL/database failure and fix it (connectivity, permissions, disk space).
  2. Verify the repository schema matches the Pentaho version in use.
  3. Retry saving the job from Spoon after restoring database access.
  4. Export the job to XML as a workaround if the repository remains unavailable.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before saveRep: ensure the repository is writable
if ( repository == null || repository.isReadOnly() ) {
  throw new KettleException( "Repository missing or read-only; cannot save job entry" );
}

Try / catch

try {
  jobEntry.saveRep( rep, id_job, id_jobentry );
} catch ( KettleException e ) {
  logError( "Failed to save mail validator job entry", e.getCause() );
  throw e;
}

Prevention

When it happens

Trigger: Calling saveRep() when the repository database connection fails, a required column is missing/null, or a constraint violation occurs while saving smtpCheck, timeout, defaultSMTP, emailSender or emailAddress.

Common situations: Repository database is read-only or disk full; schema mismatch after a Pentaho version upgrade; transaction rollback in the repository during job save; invalid characters in attribute values.

Related errors


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

Appendix: source

Thrown at plugins/mail-validator/impl/src/main/java/org/pentaho/di/job/entries/mailvalidator/JobEntryMailValidator.java:198

      emailSender = rep.getJobEntryAttributeString( id_jobentry, "emailSender" );
      emailAddress = rep.getJobEntryAttributeString( id_jobentry, "emailAddress" );
    } catch ( KettleDatabaseException dbe ) {
      throw new KettleException( BaseMessages.getString( PKG, "JobEntryMailValidator.Meta.UnableToLoadFromRep" )
        + id_jobentry, dbe );
    }
  }

  // Save the attributes of this job entry
  //
  public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_job ) throws KettleException {
    try {
      rep.saveJobEntryAttribute( id_job, getObjectId(), "smtpCheck", smtpCheck );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "timeout", timeout );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "defaultSMTP", defaultSMTP );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "emailSender", emailSender );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "emailAddress", emailAddress );
    } catch ( KettleDatabaseException dbe ) {
      throw new KettleException( BaseMessages.getString( PKG, "JobEntryMailValidator.Meta.UnableToSaveToRep" )
        + id_job, dbe );
    }
  }

  /**
   * Execute this job entry and return the result. In this case it means, just set the result boolean in the Result
   * class.
   *
   * @param previousResult
   *          The result of the previous execution
   * @return The Result of the execution.
   */
  public Result execute( Result previousResult, int nr ) {
    Result result = previousResult;
    result.setNrErrors( 1 );
    result.setResult( false );

    String realEmailAddress = environmentSubstitute( emailAddress );

View on GitHub (pinned to f3058517a1)