{"record":{"id":"1ef1531e6eee73f2","repo":"pentaho/pentaho-kettle","slug":"jobentryftpdelete-socksproxy-incompletecredentials","errorCode":"JobEntryFTPDelete.SocksProxy.IncompleteCredentials","errorMessage":"JobEntryFTPDelete.SocksProxy.IncompleteCredentials","messagePattern":"JobEntryFTPDelete\\.SocksProxy\\.IncompleteCredentials","errorType":"exception","errorClass":"FTPException","httpStatus":null,"severity":"error","filePath":"plugins/ftp-delete/impl/src/main/java/org/pentaho/di/job/entries/ftpdelete/JobEntryFTPDelete.java","lineNumber":763,"sourceCode":"      if ( protocol.equals( PROTOCOL_FTP ) ) {\n        // If socks proxy server was provided\n        if ( !Utils.isEmpty( socksProxyHost ) ) {\n          if ( !Utils.isEmpty( socksProxyPort ) ) {\n            FTPClient.initSOCKS( environmentSubstitute( socksProxyPort ), environmentSubstitute( socksProxyHost ) );\n          } else {\n            throw new FTPException( BaseMessages.getString(\n              PKG, \"JobEntryFTPDelete.SocksProxy.PortMissingException\", environmentSubstitute( socksProxyHost ),\n              getName() ) );\n          }\n          // then if we have authentication information\n          if ( !Utils.isEmpty( socksProxyUsername ) && !Utils.isEmpty( socksProxyPassword ) ) {\n            FTPClient.initSOCKSAuthentication(\n              environmentSubstitute( socksProxyUsername ), Utils.resolvePassword( this, socksProxyPassword ) );\n          } else if ( !Utils.isEmpty( socksProxyUsername )\n            && Utils.isEmpty( socksProxyPassword ) || Utils.isEmpty( socksProxyUsername )\n            && !Utils.isEmpty( socksProxyPassword ) ) {\n            // we have a username without a password or vica versa\n            throw new FTPException( BaseMessages.getString(\n              PKG, \"JobEntryFTPDelete.SocksProxy.IncompleteCredentials\",\n              environmentSubstitute( socksProxyHost ), getName() ) );\n          }\n        }\n\n        if ( copyprevious ) {\n          realFtpDirectory = \"\";\n        }\n\n        // establish the connection\n        FTPConnect(\n          realservername, realUsername, realPassword, realserverport, realFtpDirectory, realproxyhost,\n          realproxyusername, realproxypassword, realproxyport, timeoutValue );\n\n        filelist = ftpclient.dir();\n      } else if ( protocol.equals( PROTOCOL_FTPS ) ) {\n        // establish the secure connection\n        FTPSConnect( realservername, realUsername, realserverport, realPassword, realFtpDirectory, timeoutValue );","sourceCodeStart":745,"sourceCodeEnd":781,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/ftp-delete/impl/src/main/java/org/pentaho/di/job/entries/ftpdelete/JobEntryFTPDelete.java#L745-L781","documentation":"If a SOCKS proxy host is configured for the FTP protocol, SOCKS authentication requires both username and password. When exactly one of the two is provided, execute() throws FTPException with key JobEntryFTPDelete.SocksProxy.IncompleteCredentials, naming the host and job entry name.","triggerScenarios":"protocol==FTP, socksProxyHost set, and XOR condition holds: username non-empty with empty password, or password non-empty with empty username.","commonSituations":"User entered SOCKS username but left password blank (or vice versa); password stored as ${VAR} that resolves to empty; entry partially migrated from XML/repository where one field was lost.","solutions":["Provide both SOCKS username and password (or leave both empty for no auth)","Ensure the password variable resolves to a non-empty value at runtime","Clear both fields if the proxy needs no authentication","Use Utils.resolvePassword-compatible encrypted storage so the password persists"],"exampleFix":"// before\nsocksProxyUsername = \"ftpuser\";\nsocksProxyPassword = \"\"; // incomplete credentials\n// after\nsocksProxyUsername = \"ftpuser\";\nsocksProxyPassword = Encr.encryptPasswordIfNotUsingVariables( \"secret\" );","handlingStrategy":"validation","validationCode":"boolean hasUser = !Utils.isEmpty( socksProxyUsername );\nboolean hasPass = !Utils.isEmpty( Utils.resolvePassword( this, socksProxyPassword ) );\nif ( !Utils.isEmpty( socksProxyHost ) && hasUser != hasPass ) {\n  throw new FTPException( \"SOCKS proxy credentials incomplete for entry \" + getName() );\n}","typeGuard":null,"tryCatchPattern":"try { jobEntry.execute( result, 0 ); }\ncatch ( FTPException fe ) {\n  if ( String.valueOf( fe.getMessage() ).contains( \"IncompleteCredentials\" ) ) {\n    log.error( \"Provide both SOCKS username and password, or neither\" );\n  }\n}","preventionTips":["Fill both SOCKS username and password together","Verify password variables resolve to non-empty values","Re-enter credentials after migrating entries between environments"],"tags":["ftp","socks-proxy","authentication","configuration"],"backgroundTag":"missing-credentials","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"}