{"record":{"id":"0466e9a0c736a627","repo":"pentaho/pentaho-kettle","slug":"jobgetmailsfrompop-error-movetoimapfolderempty","errorCode":"JobGetMailsFromPOP.Error.MoveToIMAPFolderEmpty","errorMessage":"JobGetMailsFromPOP.Error.MoveToIMAPFolderEmpty","messagePattern":"JobGetMailsFromPOP\\.Error\\.MoveToIMAPFolderEmpty","errorType":"validation","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/email-messages/impl/src/main/java/org/pentaho/di/job/entries/getpop/JobEntryGetPOP.java","lineNumber":1077,"sourceCode":"\n    try {\n      boolean usePOP3 = getProtocol().equals( MailConnectionMeta.PROTOCOL_STRING_POP3 );\n      boolean moveAfter = false;\n      int nbrMailToRetrieve =\n        usePOP3 ? ( getRetrievemails() == 2 ? Const.toInt( getFirstMails(), 0 ) : 0 ) : Const.toInt(\n          getFirstIMAPMails(), 0 );\n\n      String realOutputFolder = createOutputDirectory( JobEntryGetPOP.FOLDER_OUTPUT );\n      String targetAttachmentFolder = createOutputDirectory( JobEntryGetPOP.FOLDER_ATTACHMENTS );\n\n      // Check destination folder\n      String realMoveToIMAPFolder = environmentSubstitute( getMoveToIMAPFolder() );\n      if ( getProtocol().equals( MailConnectionMeta.PROTOCOL_STRING_IMAP )\n        && ( getActionType() == MailConnectionMeta.ACTION_TYPE_MOVE )\n        || ( getActionType() == MailConnectionMeta.ACTION_TYPE_GET\n        && getAfterGetIMAP() == MailConnectionMeta.AFTER_GET_IMAP_MOVE ) ) {\n        if ( Utils.isEmpty( realMoveToIMAPFolder ) ) {\n          throw new KettleException( BaseMessages.getString( PKG, \"JobGetMailsFromPOP.Error.MoveToIMAPFolderEmpty\" ) );\n        }\n        moveAfter = true;\n      }\n      // check search terms\n      // Received Date\n      String realBeginDate;\n      switch ( getConditionOnReceivedDate() ) {\n        case MailConnectionMeta.CONDITION_DATE_EQUAL:\n        case MailConnectionMeta.CONDITION_DATE_GREATER:\n        case MailConnectionMeta.CONDITION_DATE_SMALLER:\n          realBeginDate = environmentSubstitute( getReceivedDate1() );\n          if ( Utils.isEmpty( realBeginDate ) ) {\n            throw new KettleException( BaseMessages.getString(\n              PKG, \"JobGetMailsFromPOP.Error.ReceivedDateSearchTermEmpty\" ) );\n          }\n          beginDate = df.parse( realBeginDate );\n          break;\n        case MailConnectionMeta.CONDITION_DATE_BETWEEN:","sourceCodeStart":1059,"sourceCodeEnd":1095,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/email-messages/impl/src/main/java/org/pentaho/di/job/entries/getpop/JobEntryGetPOP.java#L1059-L1095","documentation":"During JobEntryGetPOP.execute() validation, when the protocol is IMAP and the action is MOVE (or the after-get action is MOVE), the resolved 'Move to IMAP folder' value is checked with Utils.isEmpty; if empty, a KettleException keyed 'JobGetMailsFromPOP.Error.MoveToIMAPFolderEmpty' is thrown. A target folder is mandatory for move operations.","triggerScenarios":"JobEntryGetPOP (public execute) with protocol=IMAP and actionType=ACTION_TYPE_MOVE, or actionType=GET with afterGetIMap=AFTER_GET_IMAP_MOVE, while the (environment-substituted) MoveToIMAPFolder field is null or blank.","commonSituations":"User selected 'move mail' or 'delete after move' but left the destination folder blank; an environment variable like ${IMAP_ARCHIVE_FOLDER} is unset so the substitution yields an empty string.","solutions":["Set the 'Move to IMAP folder' field to a valid existing IMAP folder (e.g. INBOX/Archive)","If using a variable, confirm it is defined (set it in the job/kettle.properties) so substitution is non-empty","Change the after-get action from MOVE to DELETE or NOTHING if moving is not intended"],"exampleFix":"// before\n<move_to_imap_folder>${IMAP_ARCHIVE}</move_to_imap_folder> <!-- unset variable -->\n// after\n// define in kettle.properties: IMAP_ARCHIVE=INBOX/Archive\n<move_to_imap_folder>INBOX/Archive</move_to_imap_folder>","handlingStrategy":"validation","validationCode":"// before executing the job entry, mimic its check:\nString realFolder = folder == null ? null : folder.replaceAll(\"\\\\$\\\\{[^}]+\\\\}\", \"\");\nif (isMoveAction && (realFolder == null || realFolder.trim().isEmpty())) {\n  throw new IllegalArgumentException(\"MoveToIMAPFolder must be set for IMAP move actions\");\n}","typeGuard":null,"tryCatchPattern":"try { result = jobEntry.execute(prevResult, kannelTransMeta...); } catch (KettleException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"MoveToIMAPFolderEmpty\")) {\n    log.error(\"Set the destination IMAP folder or change the after-get action\");\n  }\n}","preventionTips":["Always populate 'Move to IMAP folder' when selecting a move action on IMAP","Verify any ${variables} in the folder field are defined in kettle.properties or a Set Variables entry","Run the job entry's Validate button in Spoon before scheduling"],"tags":["kettle","imap","mail","validation"],"backgroundTag":"empty-required-field","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}