pentaho/pentaho-kettle · error · FTPException

Please specify Local directory

Error message

Please specify Local directory

What it means

During FTP Put execution, the entry substitutes variables in the local directory setting and throws FTPException 'Please specify Local directory' when the resolved value is null. The local directory is mandatory — the entry must know where to read the files it will upload.

Solutions

  1. Set the Local directory field in the FTP Put job entry to a valid absolute path.
  2. If using a variable, confirm it is defined (via parameter, kettle.properties, or Set Variables) and resolves at runtime.
  3. Enable variable preview/logging to check the environmentSubstitute result before execution.
  4. Set the directory to use a file:/// URI if it references a virtual path so it resolves via URI.getPath().

Example fix

// before
localDirectory = "${MY_LOCAL_DIR}"; // variable not defined -> null

// after
localDirectory = "/opt/etl/outgoing"; // or define MY_LOCAL_DIR in kettle.properties
Defensive patterns

Strategy: validation

Validate before calling

String resolved = entry.environmentSubstitute(entry.getLocalDirectory()); if ( resolved == null || resolved.trim().isEmpty() ) { throw new IllegalArgumentException("Local directory must be set on the FTP Put entry"); }

Try / catch

try { result = runFtpPut(); } catch (FTPException e) { if ( e.getMessage().contains("Local directory") ) { failJob("Local directory not configured"); } else { throw e; } }

Prevention

When it happens

Trigger: Executing the FTP Put job entry with an empty/unset localDirectory field, or with a variable in the field (e.g. ${Internal.Job.Filename.Directory}) that resolves to null at runtime.

Common situations: Variable misspelled or not defined in the run environment; local directory field left blank when the job was cloned; running the job from a different environment (scheduler) where the variable isn't set.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at plugins/put-a-file-with-ftp/impl/src/main/java/org/pentaho/di/job/entries/ftpput/JobEntryFTPPUT.java:657

      if ( log.isDetailed() ) {
        logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.Logged", realUsername ) );
      }

      // Fix for PDI-2534 - add auxiliary FTP File List parsers to the ftpclient object.
      this.hookInOtherParsers( ftpclient );

      // move to spool dir ...
      String realRemoteDirectory = environmentSubstitute( remoteDirectory );
      if ( !Utils.isEmpty( realRemoteDirectory ) ) {
        ftpclient.chdir( realRemoteDirectory );
        if ( log.isDetailed() ) {
          logDetailed( BaseMessages.getString( PKG, "JobFTPPUT.Log.ChangedDirectory", realRemoteDirectory ) );
        }
      }

      String realLocalDirectory = environmentSubstitute( localDirectory );
      if ( realLocalDirectory == null ) {
        throw new FTPException( BaseMessages.getString( PKG, "JobFTPPUT.LocalDir.NotSpecified" ) );
      } else {
        // handle file:/// prefix
        if ( realLocalDirectory.startsWith( "file:" ) ) {
          realLocalDirectory = new URI( realLocalDirectory ).getPath();
        }
      }

      final List<String> files;
      File localFiles = new File( realLocalDirectory );
      File[] children = localFiles.listFiles();
      if ( children == null ) {
        // Unable to read local directory for some reason...
        if ( log.isDebug() ) {
          logDebug(
            BaseMessages.getString( PKG, "JobFTPPUT.Log.UnableToReadLocalDirectoryExtended", realLocalDirectory,
              Files.isReadable( localFiles.toPath() ) ) );
        } else if ( log.isBasic() ) {
          logBasic(

View on GitHub (pinned to f3058517a1)