pentaho/pentaho-kettle · error · KettleException

SSH.Error.PrivateKeyNotExist

SSH.Error.PrivateKeyNotExist

Error message

SSH.Error.PrivateKeyNotExist

What it means

SSH.Error.PrivateKeyNotExist is thrown by configureKeyAuthentication when a private key filename is provided but the file cannot be resolved through KettleVFS, i.e. the file does not exist at the given path. The step checks existence before reading the key so it can report a clear, specific error instead of an IO failure.

Solutions

  1. Correct the key file path to point at an existing file
  2. Copy the private key to the machine/node where the transformation actually executes
  3. Replace absolute paths with Kettle variables/parameters set per environment

Example fix

// before
keyFile = "/home/jenkins/.ssh/id_rsa"; // not present on worker node
// after
// copy the key first, or point to an existing one:
keyFile = "/opt/pentaho/keys/deploy_key";
Defensive patterns

Strategy: validation

Validate before calling

java.io.File f = new java.io.File(environmentSubstitute(keyFileField));
if (!f.isFile()) {
  throw new IllegalStateException("Private key not found: " + f.getAbsolutePath());
}

Prevention

When it happens

Trigger: The key file path entered in the step points to a non-existent file, or a variable in the path resolves to the wrong directory (e.g. different user home on the executing agent).

Common situations: Running the transformation on a server/node where the key file was never copied; wrong relative path (working directory differs); renamed or rotated key file.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/ssh/SSHData.java:192

      config.authType( SshConfig.AuthType.PASSWORD ).password( password );
    }
  }

  /**
   * Configures key-based authentication using secure in-memory key handling.
   * This avoids writing sensitive key data to temporary files on the filesystem.
   */
  private static void configureKeyAuthentication( SshConfig config, Bowl bowl,
      String keyFilename, String passPhrase, VariableSpace space ) throws KettleException {

    if ( Utils.isEmpty( keyFilename ) ) {
      throw new KettleException( BaseMessages.getString( PKG, "SSH.Error.PrivateKeyFileMissing" ) );
    }

    try {
      FileObject keyFileObject = KettleVFS.getInstance( bowl ).getFileObject( keyFilename );
      if ( !keyFileObject.exists() ) {
        throw new KettleException( BaseMessages.getString( PKG, "SSH.Error.PrivateKeyNotExist", keyFilename ) );
      }

      // Read key file content into memory - no temporary file needed
      FileContent keyFileContent = keyFileObject.getContent();
      byte[] keyBytes;
      try ( InputStream in = keyFileContent.getInputStream() ) {
        keyBytes = in.readAllBytes();
        if ( keyBytes.length == 0 ) {
          throw new KettleException( BaseMessages.getString( PKG, "SSH.Error.ProcessingKeyFile", keyFilename ) );
        }
      }

      // Configure SSH with in-memory key content - secure approach
      config.authType( SshConfig.AuthType.PUBLIC_KEY ).keyContent( keyBytes );

      if ( !Utils.isEmpty( passPhrase ) ) {
        config.passphrase( space.environmentSubstitute( passPhrase ) );
      }

View on GitHub (pinned to f3058517a1)