pentaho/pentaho-kettle · error · KettleException

Mail.Error.MailDestinationEmpty

Error message

Mail.Error.MailDestinationEmpty

What it means

In Mail.processRow(), the step reads the destination e-mail address from the incoming row at data.indexOfDestination. If the value is null or empty (Utils.isEmpty), it throws a KettleException with the 'Mail.Error.MailDestinationEmpty' message because an e-mail cannot be sent without a recipient.

Solutions

  1. Filter or conditionally skip rows with empty destination before the Mail step (Filter rows / Stream Lookup guard).
  2. Map the correct column as the 'To' destination field in the step dialog.
  3. Provide a fallback/default address via a 'Value Mapper', 'If field value is null' step, or coalesce logic upstream.
  4. Handle the exception (or enable step error handling) to route bad rows to an error stream instead of failing the transformation.

Example fix

// before: mail step processes every row
Mail -> (throws on empty address)
// after: guard upstream
Filter rows (destination IS NOT NULL AND destination <> '') -> Mail
Defensive patterns

Strategy: validation

Validate before calling

// before the Mail step, filter empty destinations
FilterRows: destination IS NOT NULL AND LENGTH(TRIM(destination)) > 0

Try / catch

// step error handling: route rows that throw to an error stream
stepMeta.setSupportsErrorHandling(true);
// or catch in custom code:
try {
  mail.processRow();
} catch (KettleException e) {
  if (e.getMessage().contains("MailDestinationEmpty")) {
    logError("Row has empty destination address: " + e.getMessage());
  }
}

Prevention

When it happens

Trigger: Executing the Mail step with 'To' taken from a field: the destination field exists but its value in the current row is empty/null — the row passes the field-existence check but the address column is blank.

Common situations: Upstream data has missing e-mail addresses (null contact column); a filter removed placeholder values; the wrong column is mapped as the destination field; test rows with empty addresses reach the step.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

    if ( first ) {
      first = false;

      // get the RowMeta
      data.previousRowMeta = getInputRowMeta().clone();

      validateMetaFields( meta );

      cacheFieldsPosition( meta, data );

      checkEmbeddedImages( meta, data );
    } // end if first

    try {
      // get values
      String mailDestination = data.previousRowMeta.getString( r, data.indexOfDestination );
      if ( Utils.isEmpty( mailDestination ) ) {
        throw new KettleException( "Mail.Error.MailDestinationEmpty" );
      }
      String mailDestinationCc = null;
      if ( data.indexOfDestinationCc > -1 ) {
        mailDestinationCc = data.previousRowMeta.getString( r, data.indexOfDestinationCc );
      }
      String mailDestinationBCc = null;
      if ( data.indexOfDestinationBCc > -1 ) {
        mailDestinationBCc = data.previousRowMeta.getString( r, data.indexOfDestinationBCc );
      }

      String mailSenderName = null;
      if ( data.indexOfSenderName > -1 ) {
        mailSenderName = data.previousRowMeta.getString( r, data.indexOfSenderName );
      }
      String mailSenderAddress = data.previousRowMeta.getString( r, data.indexOfSenderAddress );

      // reply addresses
      String mailReplyToAddresses = null;

View on GitHub (pinned to f3058517a1)