elastic/elasticsearch · error · SslConfigException

Error parsing Private Key [{}], file is empty

Error message

Error parsing Private Key [{}], file is empty

What it means

Thrown by PemUtils.parsePrivateKey() when the file contains no line starting with `-----BEGIN` after scanning to end of file. This is the 'no PEM content detected' error: either the file is genuinely empty, or it contains text but no PEM header at all.

Source

Thrown at libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java:136

        }
    }

    /**
     * Creates a {@link PrivateKey} from the contents of a file. Supports PKCS#1, PKCS#8
     * encoded formats of encrypted and plaintext RSA, DSA and EC(secp256r1) keys
     *
     * @param keyPath           the path for the key file
     * @param passwordSupplier A password supplier for the potentially encrypted (password protected) key
     * @return a private key from the contents of the file
     */
    static PrivateKey parsePrivateKey(Path keyPath, Supplier<char[]> passwordSupplier) throws IOException, GeneralSecurityException {
        try (BufferedReader bReader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) {
            String line = bReader.readLine();
            while (null != line && line.startsWith(HEADER) == false) {
                line = bReader.readLine();
            }
            if (null == line) {
                throw new SslConfigException("Error parsing Private Key [" + keyPath.toAbsolutePath() + "], file is empty");
            }
            if (PKCS8_ENCRYPTED_HEADER.equals(line.trim())) {
                char[] password = passwordSupplier.get();
                if (password == null) {
                    throw new SslConfigException("cannot read encrypted key [" + keyPath.toAbsolutePath() + "] without a password");
                }
                return parsePKCS8Encrypted(bReader, password);
            } else if (PKCS8_HEADER.equals(line.trim())) {
                return parsePKCS8(bReader);
            } else if (PKCS1_HEADER.equals(line.trim())) {
                return parsePKCS1Rsa(bReader, passwordSupplier);
            } else if (OPENSSL_DSA_HEADER.equals(line.trim())) {
                return parseOpenSslDsa(bReader, passwordSupplier);
            } else if (OPENSSL_DSA_PARAMS_HEADER.equals(line.trim())) {
                return parseOpenSslDsa(removeDsaHeaders(bReader), passwordSupplier);
            } else if (OPENSSL_EC_HEADER.equals(line.trim())) {
                return parseOpenSslEC(bReader, passwordSupplier);
            } else if (OPENSSL_EC_PARAMS_HEADER.equals(line.trim())) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Check the file is non-empty and starts with a PEM header: `head -1 key.pem`.
  2. If the file is binary DER, convert: `openssl pkey -inform DER -in key.der -outform PEM -out key.pem`.
  3. Re-download or re-export the key if it is empty or contains unexpected content.
  4. Confirm the configured path is correct and the file is readable: `wc -c key.pem && file key.pem`.

Example fix

# before: empty or wrong-content file
$ cat key.pem
(empty)

# after: regenerate and verify
openssl genrsa -out key.pem 2048
head -1 key.pem   # -> -----BEGIN RSA PRIVATE KEY-----
Defensive patterns

Strategy: validation

Validate before calling

public static void requireNonEmptyPem(Path p) throws IOException {
    if (Files.size(p) == 0) throw new IllegalArgumentException("file is empty: " + p);
    boolean hasHeader;
    try (BufferedReader r = Files.newBufferedReader(p, StandardCharsets.UTF_8)) {
        hasHeader = r.lines().anyMatch(l -> l.startsWith("-----BEGIN"));
    }
    if (!hasHeader) throw new IllegalArgumentException("no PEM header found in " + p);
}

Prevention

When it happens

Trigger: parsePrivateKey reads the file line by line until it finds one that starts with `-----BEGIN`. If `line` becomes null (EOF) before any such line is found, the exception fires. Typical for a 0-byte file, a file containing only whitespace/comments, or a file that is actually a binary DER mislabelled as PEM.

Common situations: Empty file created by mistake (touch without content), file overwritten by an error message (e.g. `404 not found` saved as key.pem), binary DER fed where PEM is expected, or a misconfigured path that points to `/dev/null` or an unrelated file.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/47e17384e12b7ddd. Report an issue: GitHub.