pentaho/pentaho-kettle · error · KettleException

SSH.Error.ProcessingKeyFile

SSH.Error.ProcessingKeyFile

Error message

SSH.Error.ProcessingKeyFile

What it means

SSH.Error.ProcessingKeyFile is thrown when the private key file exists but its content is empty: reading the file stream produced zero bytes. The step treats an empty key file as unusable and fails with this error, naming the key file.

Solutions

  1. Verify the key file has content (`wc -c id_rsa` / `ls -l`) and re-copy a valid private key
  2. Check that the CI/CD secret or mount that provides the key is actually populated
  3. Regenerate the key pair and deploy the new private key

Example fix

// before
-rw------- 0 bytes id_rsa  (empty file -> throws)
// after
scp valid_id_rsa worker:/opt/pentaho/keys/id_rsa  # non-empty key file
Defensive patterns

Strategy: validation

Validate before calling

java.io.File f = new java.io.File(environmentSubstitute(keyFileField));
if (f.length() == 0) {
  throw new IllegalStateException("Private key file is empty: " + f.getAbsolutePath());
}

Prevention

When it happens

Trigger: The key file path resolves to an existing but zero-byte file (truncate, failed copy, mount issue, or a placeholder file).

Common situations: CI secrets mounted as empty files when the secret is missing; interrupted scp/copy that left a 0-byte key; a directory mis-typed accidentally resolving oddly on some VFS layers.

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/c35550d74eb03871. Report an issue: GitHub.

Appendix: source

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

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

    } catch ( Exception e ) {
      throw new KettleException( BaseMessages.getString( PKG, "SSH.Error.ProcessingKeyFile", keyFilename ), e );
    }
  }

  /**
   * Configures proxy settings for the SSH connection.
   */

View on GitHub (pinned to f3058517a1)