pentaho/pentaho-kettle · error · IOException
Failed to parse SSH key content
Error message
Failed to parse SSH key content
What it means
In MinaSshConnection.loadKeys(), the key-pair provider parses raw key content bytes via SecurityUtils.loadKeyPairIdentities(). If parsing fails for any reason (malformed key, unsupported algorithm, wrong PEM/openssh format, unreadable stream), it is rethrown as IOException with this message. It signals the supplied SSH private key bytes could not be turned into a KeyPair.
Solutions
- Verify the key content is a complete private key (-----BEGIN OPENSSH/rsa PRIVATE KEY----- through matching END line, newlines intact).
- Provide the correct passphrase via config.getPassphrase() for encrypted keys.
- Convert unsupported formats: puttygen → OpenSSH format; regenerate keys with supported algorithms (RSA, ECDSA, ed25519).
- Check the wrapped cause for the exact parse failure and confirm the MINA SSHD version supports the key's algorithm.
Example fix
// before
String key = prefs.getSshKey(); // possibly a .ppk file
connection.setKeyContent(key.getBytes());
// after
if (!key.startsWith("-----BEGIN")) {
throw new KettleException("SSH key must be OpenSSH private key format, not PPK or public key");
}
connection.setKeyContent(key.getBytes(StandardCharsets.UTF_8)); Defensive patterns
Strategy: validation
Validate before calling
String key = config.getSshKeyContent();
if (key == null || !key.startsWith("-----BEGIN")) {
throw new IllegalArgumentException("SSH private key must be in OpenSSH PEM format");
} Try / catch
try {
connection.setKeyContent(keyBytes);
} catch (IOException e) {
throw new KettleException("Invalid SSH key: " + e.getCause().getMessage(), e);
} Prevention
- Store keys in OpenSSH PEM format only; convert PuTTY .ppk files with puttygen beforehand.
- Never paste public keys where private keys are expected — validate the BEGIN line.
- Keep passphrase configuration in sync with key encryption.
- Trim/preserve newlines when copying keys from secret managers.
When it happens
Trigger: loadKeyPairIdentities receives keyContent bytes that are not a parseable private key: truncated/pasted key, wrong passphrase supplier, unsupported key format (e.g. PuTTY .ppk), or encrypted key with missing/incorrect passphrase.
Common situations: User pasted a PuTTY PPK or public key instead of a private OpenSSH key; key copied without the BEGIN/END lines; passphrase changed but configuration still has the old one; key generated with an algorithm (e.g. sk-ssh-ed25519) unsupported by the bundled MINA SSHD version.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to load SSH key
- JobEntryFTPDelete.SocksProxy.IncompleteCredentials
- Password authentication failed
- SFTPPUT.Error.Connection
- SSH authentication failed
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/120e41382ede1eb5.
Report an issue: GitHub.
Appendix: source
Thrown at engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSshConnection.java:506
throw new SftpException( "Failed to open SFTP session", e );
}
}
/**
* Creates an in-memory key provider from key content bytes.
* This avoids writing sensitive key data to the filesystem.
*/
private KeyPairProvider createInMemoryKeyProvider( byte[] keyContent ) {
return new AbstractKeyPairProvider() {
@Override
public Iterable<KeyPair> loadKeys( SessionContext session ) throws IOException {
try {
// Use SecurityUtils to parse the key content directly from input stream
ByteArrayInputStream keyStream = new ByteArrayInputStream( keyContent );
return SecurityUtils.loadKeyPairIdentities( session, null,
keyStream, ( s, r, i ) -> config.getPassphrase() );
} catch ( Exception e ) {
throw new IOException( "Failed to parse SSH key content", e );
}
}
};
}
@Override
public void close() {
if ( session != null ) {
session.close( false );
}
if ( client != null ) {
client.stop();
}
}
}
View on GitHub (pinned to f3058517a1)