pentaho/pentaho-kettle · error · KettleException

JobTrans.Exception.UnableToFindRemoteSlaveServer

Error message

JobTrans.Exception.UnableToFindRemoteSlaveServer

What it means

When the Job entry is configured to run the sub-job on a cluster/slave (executing remotely), execute() looks up the slave server by its (variable-substituted) name via parentJob.getJobMeta().findSlaveServer(). If no registered slave server matches, this KettleException with message 'JobTrans.Exception.UnableToFindRemoteSlaveServer' (with the name) is thrown.

Solutions

  1. Verify the slave server name in the entry dialog exactly matches a slave defined in the job's cluster schema / slave server list
  2. Check that any variable in the remote slave server field resolves correctly at runtime
  3. Re-add or restore the missing slave server definition in Spoon
  4. Log the substituted name (environmentSubstitute(remoteSlaveServerName)) and compare against available slave servers

Example fix

// before: Slave server name: ${SLAVE_HOST}
// after: fail fast with a defined default
setVariable("SLAVE_HOST", Const.NVL(getVariable("SLAVE_HOST"), "slave1"));
// and in code, validate before execute:
if (parentJob.getJobMeta().findSlaveServer(environmentSubstitute(remoteSlaveServerName)) == null) {
  throw new KettleException("Configured slave not registered: " + remoteSlaveServerName);
}
Defensive patterns

Strategy: validation

Validate before calling

String realName = jobEntry.environmentSubstitute(jobEntry.getRemoteSlaveServerName());
if (realName != null && !realName.isEmpty()
    && parentJob.getJobMeta().findSlaveServer(realName) == null) {
  throw new IllegalArgumentException("Slave server not registered: " + realName);
}

Try / catch

try {
  jobEntry.execute(result, nr);
} catch (KettleException e) {
  if (e.getMessage().contains("UnableToFindRemoteSlaveServer")) {
    // log available slave servers and abort; do not retry blindly
  }
  throw e;
}

Prevention

When it happens

Trigger: Executing remotely with remoteSlaveServerName set (e.g. 'slave1' or '${SLAVE}') where findSlaveServer() returns null — the name doesn't match any slave defined in the job meta / cluster schema, or the variable substitutes to a misspelled/unknown name.

Common situations: Typo in slave server name; variable not defined so it substitutes literally; slave server deleted from the cluster schema; moving the job between environments where slave registry differs.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/job/entries/job/JobEntryJob.java:937

            }
            remoteSlaveServer = executionConfiguration.getRemoteServer();
            doFallback = false;
          } catch ( KettleException e ) {
            log.logError( e.getMessage(), getName() );
            result.setNrErrors( 1 );
            result.setResult( false );
            return result;
          }
        }

        if ( doFallback ) {
          // Figure out the remote slave server...
          //
          if ( !Utils.isEmpty( remoteSlaveServerName ) ) {
            String realRemoteSlaveServerName = environmentSubstitute( remoteSlaveServerName );
            remoteSlaveServer = parentJob.getJobMeta().findSlaveServer( realRemoteSlaveServerName );
            if ( remoteSlaveServer == null ) {
              throw new KettleException( BaseMessages.getString(
                PKG, "JobTrans.Exception.UnableToFindRemoteSlaveServer", realRemoteSlaveServerName ) );
            }
          }
        }

        if ( remoteSlaveServer == null ) {
          // Local execution...
          //

          // Create a new job
          //
          job = new Job( rep, jobMeta, this );
          job.setParentJob( parentJob );
          job.setLogLevel( jobLogLevel );
          job.shareVariablesWith( this );
          job.setInternalKettleVariables( this );
          job.copyParametersFrom( jobMeta );
          job.setInteractive( parentJob.isInteractive() );

View on GitHub (pinned to f3058517a1)