pentaho/pentaho-kettle · critical · SshConnectionException
SSH connection failed -
Error message
SSH connection failed -
What it means
MinaSshConnection.createConnection() catches any Exception during SSH session establishment and rethrows it as SshConnectionException with message built from buildConnectionErrorMessage(e). It is the generic connect-failure path; the specific reason (refused, auth, key, timeout) is in the cause and the enriched message.
Solutions
- Read the full message/cause to get the concrete failure (refused vs auth vs algorithm negotiation)
- Test basic reachability: ping/telnet to host:port from the same machine
- Verify username/password or key file and passphrase are correct and the key format is supported (OpenSSH/PEM)
- If the server only offers legacy algorithms, enable them in the SSH client or update the server; upgrade the MINA SSHD library if negotiation fails
- Check proxy configuration if isProxyConfigured() is true, since the proxy path is exercised instead of the direct one
Example fix
// before
SshConnection conn = new MinaSshConnection(config);
conn.connect(); // opaque failure
// after
try {
conn.connect();
} catch (SshConnectionException e) {
log.error("SSH connect to {}:{} failed: {}", config.getHost(), config.getPort(), e.getMessage(), e.getCause());
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-flight before connect()
if (config.getHost() == null || config.getHost().isBlank()) throw new IllegalArgumentException("host required");
if (config.getPort() <= 0) throw new IllegalArgumentException("port required");
try (Socket s = new Socket()) { s.connect(new InetSocketAddress(config.getHost(), config.getPort()), 5000); }
catch (IOException e) { throw new IllegalStateException("host:port unreachable before SSH attempt", e); } Type guard
boolean reachable(String host, int port) {
try (Socket s = new Socket()) { s.connect(new InetSocketAddress(host, port), 5000); return true; }
catch (IOException e) { return false; }
} Try / catch
try {
conn.connect();
} catch (SshConnectionException e) {
Throwable root = e;
while (root.getCause() != null) root = root.getCause();
log.error("SSH connect failed (root cause: {}): {}", root.getClass().getSimpleName(), root.getMessage());
throw e;
} Prevention
- Pre-flight TCP reachability of host:port before the SSH handshake
- Validate credentials/key paths and passphrases in config before connecting
- Align cipher/KEX algorithms with the server (test with ssh -vv); upgrade the MINA SSHD library if needed
- Unwrap and log the root cause chain — this error message alone hides the real reason
When it happens
Trigger: Calling connect() when the host is unreachable/port closed, credentials or key auth rejected, no supported key exchange/cipher negotiated, or the proxy path throws an unexpected exception type.
Common situations: Wrong host/port in the SSH connection metadata, SSH server firewalling the client, unsupported or passphrase-protected private key without a supplied passphrase, server disabled the auth method the client tries, or MINA SSHD version incompatibility with the server's algorithms.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- SSH.Error.ErrorConnecting
- Failed to open SFTP session
- SFTPPUT.Error.Connection
- SSH connection failed during await
- CmsTokenProvider: Keycloak token request failed — HTTP
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/cf14ab95170dcb56.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSshConnection.java:135
client = SshClient.setUpDefaultClient();
// Disable strict host key checking to avoid key exchange issues
client.setServerKeyVerifier( ( clientSession, remoteAddress, serverKey ) -> true );
client.start();
}
private ConnectFuture createConnection() throws SshConnectionException {
try {
if ( isProxyConfigured() ) {
return createProxyConnection();
} else {
return createDirectConnection();
}
} catch ( SshConnectionException e ) {
throw e; // Re-throw SshConnectionException as-is
} catch ( Exception e ) {
throw new SshConnectionException( buildConnectionErrorMessage( e ), e );
}
}
private boolean isProxyConfigured() {
return config.getProxyHost() != null && !config.getProxyHost().trim().isEmpty();
}
private ConnectFuture createDirectConnection() throws IOException {
log( DEBUG, "SSH Direct Connection: " + config.getHost() + ":" + config.getPort()
+ formatUserInfo() );
return client.connect( config.getUsername(), config.getHost(), config.getPort() );
}
private ConnectFuture createProxyConnection() throws SshConnectionException, IOException {
log( BASIC, "SSH over HTTP Proxy: " + config.getProxyHost() + ":" + config.getProxyPort()
+ " -> " + config.getHost() + ":" + config.getPort() );
log( DEBUG, "HTTP Proxy Details - Target User: " + config.getUsername() + ", Auth: " + config.getAuthType() );
View on GitHub (pinned to f3058517a1)