pentaho/pentaho-kettle · error · KettleException

SSH.Error.MessageEmpty

SSH.Error.MessageEmpty

Error message

SSH.Error.MessageEmpty

What it means

The SSH step throws SSH.Error.MessageEmpty when the step is configured to take its SSH command from a field in the incoming row (dynamic command), but the value read from that field is empty or null. The step refuses to execute an empty command because there is nothing to send to the remote host. It is thrown from processRow before any connection is established.

Solutions

  1. Verify the 'field name containing the command' setting points to the correct existing field in the stream
  2. Fix the upstream step so the command field is populated for every row
  3. Add a Filter/IF step to route rows with empty commands away from the SSH step
  4. Switch back to a static command in the step dialog if a fixed command is intended

Example fix

// before
rowCommandField = "cmd"; // field not present or empty in stream
// after
// ensure upstream generates the value:
// Put a 'Data Grid' or 'JavaScript' step setting cmd = "ls -l /tmp"; then set the SSH step field to "cmd"
Defensive patterns

Strategy: validation

Validate before calling

// before running the transformation, in an upstream step (UDJE/JS):
if (field == null || field.trim().isEmpty()) {
  throw new RuntimeException("SSH command field is empty for row " + getRowNumber());
}

Prevention

When it happens

Trigger: Running the SSH step with 'Execute command from field' (isDynamicCommand=true) while the command field in the incoming row is null or an empty string.

Common situations: The selected command field name changed upstream; a previous step emits null/empty values for some rows; wrong field index configured after editing the transformation.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/ssh/SSH.java:120

    RowMetaInterface imeta = getInputRowMeta();
    if ( imeta == null ) {
      imeta = new RowMeta();
      this.setInputRowMeta( imeta );
    }
    // Reserve room
    Object[] rowData = new Object[ data.nrOutputFields ];
    for ( int i = 0; i < data.nrInputFields; i++ ) {
      rowData[ i ] = row[ i ]; // no data is changed, clone is not needed here.
    }
    int index = data.nrInputFields;

    try {
      if ( meta.isDynamicCommand() ) {
        // get commands
        data.commands = data.outputRowMeta.getString( row, data.indexOfCommand );
        if ( Utils.isEmpty( data.commands ) ) {
          throw new KettleException( BaseMessages.getString( PKG, "SSH.Error.MessageEmpty" ) );
        }
      }

      // Connect if not already connected
      if ( !data.isConnected() ) {
        data.getSshConnection().connect();
        data.setConnected( true );
        if ( log.isDebug() ) {
          logDebug( BaseMessages.getString( PKG, "SSH.Log.SessionOpened" ) );
        }
      }

      // execute commands
      if ( log.isDetailed() ) {
        logDetailed( BaseMessages.getString( PKG, "SSH.Log.RunningCommand", data.commands ) );
      }
      ExecResult execResult = data.getSshConnection().exec( data.commands );

View on GitHub (pinned to f3058517a1)