pentaho/pentaho-kettle · error · SftpException

Failed to open SFTP session

Error message

Failed to open SFTP session

What it means

MinaSshConnection.openSftp() wraps any exception raised while creating an SFTP subsystem channel on top of an established Apache MINA SSHD session into a SftpException with this message. The SSH transport session already succeeded; the failure is specifically in opening the SFTP client/subsystem on that session. The original cause (server refusing the sftp subsystem, timeout, channel closed) is attached as the cause.

Solutions

  1. Inspect the wrapped cause with e.getCause() to see the real failure from MINA SSHD.
  2. Verify the SSH server has the sftp subsystem enabled (Subsystem sftp internal-sftp or sftp-server binary path in sshd_config).
  3. Reopen/refresh the SSH session if it was closed or timed out before calling openSftp.
  4. Confirm the authenticated user is permitted to use SFTP (not shell-only or chroot-restricted incorrectly).

Example fix

// before
SftpSession sftp = connection.openSftp();
// after
SftpSession sftp;
try {
  if (!connection.isOpen()) connection.open();
  sftp = connection.openSftp();
} catch (SftpException e) {
  throw new KettleException("SFTP subsystem unavailable on " + host + ": " + e.getCause(), e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (connection == null || !connection.isOpen()) {
  connection.open(); // ensure the SSH session is alive before requesting SFTP
}

Try / catch

try {
  SftpSession sftp = connection.openSftp();
} catch (SftpException e) {
  logError("SFTP open failed: " + (e.getCause() != null ? e.getCause().getMessage() : e.getMessage()), e);
  // reconnect session and retry once, or fail the step with actionable message
}

Prevention

When it happens

Trigger: Calling SftpClientFactory.instance().createSftpClient(session) fails: the server does not support or denies the 'sftp' subsystem, the session has been closed/disconnected before the call, or an I/O error occurs while opening the channel.

Common situations: SSH server (e.g. hardened OpenSSH with Subsystem sftp disabled or restricted via ChrootDirectory/ForceCommand internal-sftp) refuses the subsystem; connection idle-timed out and the session is dead; firewall drops the channel; user lacks permission for SFTP access.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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

Appendix: source

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

      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() );
  }

  @Override
  public SftpSession openSftp() throws SshConnectionException {
    try {
      var factory = SftpClientFactory.instance();
      var sftp = factory.createSftpClient( session );
      return new MinaSftpSession( sftp );
    } catch ( Exception e ) {
      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 );

View on GitHub (pinned to f3058517a1)