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
- Verify the 'field name containing the command' setting points to the correct existing field in the stream
- Fix the upstream step so the command field is populated for every row
- Add a Filter/IF step to route rows with empty commands away from the SSH step
- 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
- Always validate the command field is non-empty before the SSH step
- Add a Filter step routing empty-command rows to a dead-letter path
- Lock the command field name in transformation metadata and review on refactor
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
- Command execution timed out after
- Command execution was interrupted
- Failed to check if path is directory:
- Failed to create directory:
- Failed to delete:
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)