pentaho/pentaho-kettle · error · KettleException

JobGetMailsFromPOP.Error.AttachmentFolderNotAFolder

Error message

JobGetMailsFromPOP.Error.AttachmentFolderNotAFolder

What it means

Same check as the output-folder variant but for FOLDER_ATTACHMENTS: if the resolved attachments folder path exists on the VFS but is not a directory (FileType != FOLDER), this KettleException is thrown with the folder name as a parameter. The entry cannot write attachments into a non-directory.

Solutions

  1. Move/delete the file occupying the configured attachments path so a directory can be used there.
  2. Correct the 'Attachments directory' field to reference a directory path.
  3. Verify variable substitution output resolves to a directory, not a file path.

Example fix

// before
attachments dir = /data/attachments.zip (file)
// after
attachments dir = /data/attachments      (directory)
Defensive patterns

Strategy: validation

Validate before calling

File att = new File(environmentSubstitute(getAttachmentFolder()));
if (att.exists() && !att.isDirectory()) {
  throw new IllegalArgumentException("Attachments path exists but is not a directory: " + att);
}

Try / catch

try { executeJobEntry(); } catch (KettleException e) {
  if (e.getMessage().contains("AttachmentFolderNotAFolder")) {
    logError("Configured attachments path is a file, not a directory: " + e.getMessage());
  } else { throw e; }
}

Prevention

When it happens

Trigger: createOutputDirectory(FOLDER_ATTACHMENTS) with folder.exists() true and folder.getType() != FileType.FOLDER — the attachments path resolves to an existing regular file.

Common situations: Attachments directory points at an existing file; a mis-typed path like /data/attach.tar where /data/attach was intended; variable expansion appends a filename instead of a directory name.

Related errors


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

Appendix: source

Thrown at plugins/email-messages/impl/src/main/java/org/pentaho/di/job/entries/getpop/JobEntryGetPOP.java:1593

        break;
    }
    if ( Utils.isEmpty( folderName ) ) {
      switch ( folderType ) {
        case JobEntryGetPOP.FOLDER_OUTPUT:
          throw new KettleException( BaseMessages.getString( PKG, "JobGetMailsFromPOP.Error.OutputFolderEmpty" ) );
        case JobEntryGetPOP.FOLDER_ATTACHMENTS:
          throw new KettleException( BaseMessages.getString( PKG, "JobGetMailsFromPOP.Error.AttachmentFolderEmpty" ) );
      }
    }
    FileObject folder = KettleVFS.getInstance( parentJobMeta.getBowl() ).getFileObject( folderName, this );
    if ( folder.exists() ) {
      if ( folder.getType() != FileType.FOLDER ) {
        switch ( folderType ) {
          case JobEntryGetPOP.FOLDER_OUTPUT:
            throw new KettleException( BaseMessages.getString(
              PKG, "JobGetMailsFromPOP.Error.NotAFolderNot", folderName ) );
          case JobEntryGetPOP.FOLDER_ATTACHMENTS:
            throw new KettleException( BaseMessages.getString(
              PKG, "JobGetMailsFromPOP.Error.AttachmentFolderNotAFolder", folderName ) );
        }
      }
      if ( isDebug() ) {
        switch ( folderType ) {
          case JobEntryGetPOP.FOLDER_OUTPUT:
            logDebug( BaseMessages.getString( PKG, "JobGetMailsFromPOP.Log.OutputFolderExists", folderName ) );
            break;
          case JobEntryGetPOP.FOLDER_ATTACHMENTS:
            logDebug( BaseMessages.getString( PKG, "JobGetMailsFromPOP.Log.AttachmentFolderExists", folderName ) );
            break;
        }
      }
    } else {
      if ( isCreateLocalFolder() ) {
        folder.createFolder();
      } else {
        switch ( folderType ) {

View on GitHub (pinned to f3058517a1)