pentaho/pentaho-kettle · error · KettleException

SSH.Exception.CouldnotFindField

SSH.Exception.CouldnotFindField

Error message

SSH.Exception.CouldnotFindField

What it means

SSH step's processRow(), in dynamic-command mode, caches data.indexOfCommand = outputRowMeta.indexOfValue(commandFieldName); if the field is not present in the row stream (index < 0) it throws KettleException 'SSH.Exception.CouldnotFindField' with the field name as parameter. The step cannot execute commands because the configured command field does not exist in incoming rows.

Solutions

  1. Check upstream steps' output fields (right-click -> Show output fields) and set the SSH step's command field to an existing name
  2. Fix case sensitivity: field names must match exactly (e.g. 'CMD' vs 'cmd')
  3. Reconnect the correct hop so the row stream actually contains the command field
  4. Re-run Get Fields / reopen the dialog after upstream changes to refresh the selection

Example fix

// before (upstream field renamed)
meta.setcommandfieldname( "command" ); // upstream produces 'cmd'
// after
meta.setcommandfieldname( "cmd" ); // matches upstream output field
Defensive patterns

Strategy: type-guard

Validate before calling

// Before running, confirm the field exists in the previous step's output:
RowMetaInterface prev = transMeta.getPrevStepFields( sshStepMeta );
String cmdField = meta.getcommandfieldname();
if ( cmdField == null || prev.indexOfValue( cmdField ) < 0 ) {
  throw new IllegalStateException( "SSH step: field '" + cmdField + "' not found in upstream rows" );
}

Type guard

boolean commandFieldExists( RowMetaInterface rowMeta, String fieldName ) {
  return fieldName != null && rowMeta != null && rowMeta.indexOfValue( fieldName ) >= 0;
}

Try / catch

try {
  sshStep.processRow();
} catch ( KettleException e ) {
  if ( e.getMessage().contains( "CouldnotFindField" ) ) {
    // inspect upstream output fields and fix the configured field name
  }
}

Prevention

When it happens

Trigger: The 'command field name' setting names a field that no upstream step produces: typo, upstream step removed/renamed, field renamed after configuring the SSH step, or field added on a branch that doesn't feed this step.

Common situations: Renaming an upstream 'Add constants' or text-input field and forgetting to update the SSH step; connecting the SSH step to the wrong hop; case mismatch between configured name and actual field (Kettle field lookup is case-sensitive).

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — 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/6f8b41d3fad86a73. Report an issue: GitHub.

Appendix: source

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

      }
      if ( first ) {
        first = false;
        data.outputRowMeta = getInputRowMeta().clone();
        data.nrInputFields = data.outputRowMeta.size();
        meta.getFields( getTransMeta().getBowl(), data.outputRowMeta, getStepname(), null, null, this, repository,
          metaStore );
        data.nrOutputFields = data.outputRowMeta.size();

        // Check if commands field is provided
        if ( meta.isDynamicCommand() ) {
          if ( Utils.isEmpty( meta.getcommandfieldname() ) ) {
            throw new KettleException( BaseMessages.getString( PKG, "SSH.Error.CommandFieldMissing" ) );
          }
          // cache the position of the source filename field
          data.indexOfCommand = data.outputRowMeta.indexOfValue( meta.getcommandfieldname() );
          if ( data.indexOfCommand < 0 ) {
            // The field is unreachable !
            throw new KettleException( BaseMessages.getString( PKG, "SSH.Exception.CouldnotFindField", meta
              .getcommandfieldname() ) );
          }
        }
      }
    } else {
      if ( !data.wroteOneRow ) {
        row = new Object[] {}; // empty row
        incrementLinesRead();
        data.wroteOneRow = true;
        if ( first ) {
          first = false;
          data.outputRowMeta = new RowMeta();
          data.nrInputFields = 0;
          meta.getFields( getTransMeta().getBowl(), data.outputRowMeta, getStepname(), null, null, this, repository,
            metaStore );
          data.nrOutputFields = data.outputRowMeta.size();
          data.commands = environmentSubstitute( meta.getCommand() );
        }

View on GitHub (pinned to f3058517a1)