apache/pulsar · error · KeyManagementException

Private key loading error

Error message

Private key loading error

What it means

PemReader.loadPrivateKeyFromPemFile reads the PEM private-key file and delegates to loadPrivateKeyFromPemStream. Any IOException while reading the file (missing file, permissions, I/O failure) is wrapped into KeyManagementException('Private key loading error').

Source

Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/tls/PemReader.java:149

     * Load a PKCS#8 PEM private key, manufacturing the key object with a pinned JCA provider.
     *
     * @param keyFilePath the PEM file path
     * @param jcaProvider the pinned JCA provider, or {@code null} for the JVM provider search order
     * @return the loaded private key, or {@code null} when no path was given
     * @throws KeyManagementException if the key cannot be loaded
     */
    public static PrivateKey loadPrivateKeyFromPemFile(String keyFilePath, Provider jcaProvider)
            throws KeyManagementException {
        if (keyFilePath == null || keyFilePath.isEmpty()) {
            return null;
        }

        PrivateKey privateKey;

        try (FileInputStream input = new FileInputStream(keyFilePath)) {
            privateKey = loadPrivateKeyFromPemStream(input, jcaProvider);
        } catch (IOException e) {
            throw new KeyManagementException("Private key loading error", e);
        }

        return privateKey;
    }

    public static PrivateKey loadPrivateKeyFromPemStream(InputStream inStream) throws KeyManagementException {
        return loadPrivateKeyFromPemStream(inStream, null);
    }

    /**
     * Load a PKCS#8 PEM private key from a stream, manufacturing the key object with a pinned JCA provider.
     *
     * <p>The existing per-algorithm loop degrades naturally: an algorithm the pinned provider does not supply
     * is skipped like an algorithm that does not match the key, and the same loud "algorithm is not supported"
     * error is thrown when none of them works.
     *
     * @param inStream    the PEM stream
     * @param jcaProvider the pinned JCA provider, or {@code null} for the JVM provider search order

View on GitHub (pinned to 820761864e)

Solutions

  1. Verify the key file path exists and is readable (ls -l, container mounts, secret names)
  2. Fix the configured tlsKeyFilePath / mount the secret volume correctly
  3. Check the wrapped cause in the stack trace to confirm it is I/O vs parsing (parsing failures are raised by loadPrivateKeyFromPemStream instead)
  4. Ensure the key is in a PEM format the reader supports (unencrypted PKCS#8/SEC1) and permissions are e.g. 600 for the service user

Example fix

// before
tlsKeyFilePath=/secrets/broker.key.pem   // secret not mounted
// after
// mount the secret and set readable perms:
// chmod 600 /secrets/broker.key.pem
File f = new File(path);
if (!f.canRead()) throw new IllegalStateException("key file missing: " + path);
Defensive patterns

Strategy: try-catch

Validate before calling

File f = new File(keyPath);
if (!f.isFile() || !f.canRead()) throw new IllegalStateException("Unreadable key file: " + keyPath);

Try / catch

try { return PemReader.loadPrivateKeyFromPemFile(path); } catch (KeyManagementException e) { log.error("Failed loading private key from {}: {}", path, e.getCause()); throw new IllegalStateException("Invalid TLS key configuration", e); }

Prevention

When it happens

Trigger: Key file path is wrong or the file does not exist (FileNotFoundException); process lacks read permission on the key file; I/O error while streaming (truncated file, failing volume).

Common situations: Misconfigured tlsKeyFilePath on broker/client; Kubernetes secret not mounted or wrong mount path; key file rotated/renamed while the process held a stale path; running in a hardened container where the secret file permissions are too restrictive.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/d606ff8c23ad25d8. Report an issue: GitHub.