pentaho/pentaho-kettle · error · SshAuthenticationException

Failed to load SSH key

Error message

Failed to load SSH key

What it means

tryPublicKeyAuthentication wraps any IOException or GeneralSecurityException from loading/using the key pair into SshAuthenticationException('Failed to load SSH key'). The private key material could not be read, decrypted, or parsed before authentication could even be attempted.

Solutions

  1. Verify the key file exists, is readable, and is a supported format (OpenSSH/PEM, not PuTTY .ppk)
  2. Correct the passphrase — an encrypted key needs its passphrase in config
  3. Convert the key: ssh-keygen -p -m PEM -f id_rsa if the parser rejects the format
  4. If using key content, paste the full key including BEGIN/END header lines
  5. Upgrade the SSHD library if the key uses a newer format (e.g. ed25519-sk)

Example fix

// before
config.setKeyContent( Files.readString( Path.of( "id_rsa" ) ).trim() ); // header stripped breaks parse
// after
config.setKeyContent( Files.readString( Path.of( "id_rsa" ) ) ); // keep full PEM including BEGIN/END lines
Defensive patterns

Strategy: validation

Validate before calling

// validate key before connect()
String key = config.getKeyContent() != null ? config.getKeyContent() : Files.readString( Path.of( keyPath ) );
if ( !key.contains( "BEGIN" ) || !key.contains( "PRIVATE KEY" ) ) {
  throw new IllegalArgumentException( "Key is not a valid PEM/OpenSSH private key" );
}
if ( key.contains( "ENCRYPTED" ) && ( config.getPassphrase() == null || config.getPassphrase().isEmpty() ) ) {
  throw new IllegalArgumentException( "Key is encrypted but no passphrase configured" );
}

Try / catch

try { conn.connect(); }
catch ( SshAuthenticationException e ) {
  if ( e.getMessage().contains( "Failed to load SSH key" ) ) {
    log.error( "Key load failed: check format (PEM/OpenSSH, not .ppk), passphrase, and file readability", e.getCause() );
  } else throw e;
}

Prevention

When it happens

Trigger: Key content (in-memory) or key file is malformed/unsupported format, the passphrase is wrong or missing for an encrypted key, or the key file path is unreadable — raised inside loadKeysIntoSession/KeyPairProvider usage.

Common situations: PEM vs OpenSSH new-format keys not supported by the bundled SSHD version; wrong passphrase; key file permissions; empty key content field in the connection dialog; PKCS#8/PPK formats.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/dbb58ba59ee3a8fe. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/core/ssh/mina/MinaSshConnection.java:320

      log( DEBUG, "Skipping public key authentication - not configured" );
      return false;
    }

    log( DEBUG, "Attempting SSH public key authentication" );

    try {
      KeyPairProvider keyPairProvider = loadKeyPairProvider();
      if ( keyPairProvider == null ) {
        return false;
      }

      configurePassphrase( keyPairProvider );
      loadKeysIntoSession( keyPairProvider );

      return performPublicKeyAuth();
    } catch ( IOException | GeneralSecurityException e ) {
      log( ERROR, "SSH public key authentication error: " + e.getMessage(), e );
      throw new SshAuthenticationException( "Failed to load SSH key", e );
    }
  }

  private KeyPairProvider loadKeyPairProvider() {
    if ( config.getKeyContent() != null ) {
      log( DEBUG, "Using in-memory SSH key content" );
      return createInMemoryKeyProvider( config.getKeyContent() );
    }

    if ( config.getKeyPath() != null ) {
      log( DEBUG, "Loading SSH key from file: " + config.getKeyPath() );
      Path key = config.getKeyPath();
      if ( !Files.exists( key ) ) {
        log( ERROR, "SSH key file does not exist: " + key );
        return null;
      }
      return new FileKeyPairProvider( List.of( key ) );
    }

View on GitHub (pinned to f3058517a1)