pentaho/pentaho-kettle · error · SshTimeoutException
Command execution timed out after
Error message
Command execution timed out after ${timeoutMs}ms What it means
exec(command, timeoutMs) polls the channel's exit status and, when the wait window elapses before the remote command completes, throws SshTimeoutException('Command execution timed out after Nms'). The command may still be running remotely; the client simply stopped waiting.
Solutions
- Increase commandTimeoutMillis to exceed the command's worst-case duration
- Fix the remote command to run non-interactively (no prompts, redirect stdin)
- Run long jobs with nohup/background on the remote host and poll for completion
- Verify the command is not blocked waiting for input (test interactively)
- Break the work into smaller commands within the timeout window
Example fix
// before ExecResult r = conn.exec( "/opt/etl/run-all.sh", 30000 ); // 30s, job takes minutes // after ExecResult r = conn.exec( "/opt/etl/run-all.sh", 1800000 ); // 30min budget // or: nohup /opt/etl/run-all.sh > /tmp/etl.log 2>&1 & then poll
Defensive patterns
Strategy: try-catch
Validate before calling
// estimate: ensure timeout exceeds worst-case command duration
long expectedMaxMillis = estimateCommandDuration( command );
if ( config.getCommandTimeoutMillis() < expectedMaxMillis ) {
log.warn( "Command timeout {}ms is below expected duration {}ms", config.getCommandTimeoutMillis(), expectedMaxMillis );
} Try / catch
try { result = conn.exec( cmd, timeoutMs ); }
catch ( SshTimeoutException e ) {
log.warn( "Command exceeded {}ms; it may still be running remotely", timeoutMs );
// optionally reconnect and kill/check the remote process before retrying
} Prevention
- Size the timeout from the command's worst-case runtime, not its average
- Make remote commands non-interactive (no prompts)
- Run long jobs in the background on the host and poll for completion
- Monitor execution times to recalibrate timeouts
When it happens
Trigger: exec() is called with commandTimeoutMillis > 0 and the remote command does not produce an exit status within that period — long-running scripts, hung remote processes, or output waiting on a TTY prompt.
Common situations: Running backups/ETL scripts that exceed the default command timeout; remote command waiting on a password/passphrase prompt; remote host under load.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Failed to execute command
- SSH connection failed while waiting with no configured…
- SSH connection timed out after ms
- Command execution was interrupted
- Failed to check if path is directory:
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/b147aa3665003582.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSshConnection.java:460
}
// Wait for the command to complete and exit status to be available
Set<ClientChannelEvent> events = ch.waitFor(
EnumSet.of( ClientChannelEvent.CLOSED ), timeoutMs );
// Give a bit more time for exit status to be set if the channel closed successfully
if ( events.contains( ClientChannelEvent.CLOSED ) ) {
// Try to get exit status with a short additional wait
Integer ex = ch.getExitStatus();
if ( ex == null ) {
// Wait a bit more for exit status to be set
Thread.sleep( 100 );
ex = ch.getExitStatus();
}
exit = ex == null ? -1 : ex;
} else {
// Timeout occurred
throw new SshTimeoutException( "Command execution timed out after " + timeoutMs + "ms" );
}
}
String outStr = stdout.toString( StandardCharsets.UTF_8 );
String errStr = stderr.toString( StandardCharsets.UTF_8 );
return new ExecResult( outStr, errStr, outStr + errStr, exit, exit != 0 );
} catch ( SshTimeoutException e ) {
throw e; // Re-throw timeout exceptions as-is
} catch ( InterruptedException e ) {
Thread.currentThread().interrupt(); // Restore interrupted status
throw new SshConnectionException( "Command execution was interrupted", e );
} catch ( Exception e ) {
throw new SshConnectionException( "Failed to execute command: " + command, e );
}
}
@Override
public ExecResult exec( String command ) throws SshConnectionException {
return exec( command, config.getCommandTimeoutMillis() );View on GitHub (pinned to f3058517a1)