quarkusio/quarkus · error · IllegalStateException

The file <path> does not contain a private key <type>

Error message

The file <path> does not contain a private key <type>

What it means

When generating a CA-signed certificate, the CLI loads the certificate authority private key from a fixed file (Constants.PK_FILE, typically the CA's PEM private key) using BouncyCastle's PEMParser. If the first PEM object parsed from that file is neither a KeyPair nor a PrivateKeyInfo (e.g. it is a certificate, an encrypted private key, or a public key), loadPrivateKey throws this IllegalStateException naming the actual parsed Java class. It is a guard against using a file that does not hold a usable CA private key.

Source

Thrown at extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/GenerateCertificateCommand.java:154

    private X509Certificate loadRootCertificate(File ca) throws Exception {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        try (FileInputStream fis = new FileInputStream(ca)) {
            return (X509Certificate) cf.generateCertificate(fis);
        }
    }

    private PrivateKey loadPrivateKey() throws Exception {
        try (BufferedReader reader = new BufferedReader(new FileReader(Constants.PK_FILE));
                PEMParser pemParser = new PEMParser(reader)) {
            Object obj = pemParser.readObject();
            if (obj instanceof KeyPair) {
                return ((KeyPair) obj).getPrivate();
            } else if (obj instanceof PrivateKeyInfo) {
                JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
                return converter.getPrivateKey(((PrivateKeyInfo) obj));
            } else {
                throw new IllegalStateException(
                        "The file " + Constants.PK_FILE.getAbsolutePath() + " does not contain a private key "
                                + obj.getClass().getName());
            }
        }
    }

    private void createSignedCertificate(X509Certificate issuerCert,
            PrivateKey issuerPrivateKey) throws Exception {
        if (!Files.exists(directory)) {
            Files.createDirectories(directory);
        }
        AUDIT.debug("Generating CA-signed certificate - name: " + name + ", cn: " + cn);
        new CertificateGenerator(directory, renew).generate(new CertificateRequest()
                .withName(name)
                .withCN(cn)
                .withPassword(password)
                .withDuration(Duration.ofDays(365))
                .withFormat(Format.PKCS12)

View on GitHub (pinned to e1c734241f)

Solutions

  1. Verify the file at the reported path actually contains the CA private key PEM block (BEGIN PRIVATE KEY / BEGIN RSA PRIVATE KEY / BEGIN EC PRIVATE KEY), not the certificate
  2. If the CA key is encrypted, decrypt it first (openssl pkcs8 -topk8 -nocrypt -in ca.key -out ca-decrypted.key) and point the tooling at the unencrypted key
  3. Restore the correct key file (re-export from your keystore or regenerate the CA if lost, then re-issue certificates)
  4. Re-run the command; the exception message prints the parsed class name (e.g. org.bouncycastle.asn1.x509.Certificate) telling you exactly what the file contains

Example fix

// before: file contains the CA certificate, PEMParser reads an X509Certificate -> IllegalStateException
openssl x509 -in ca.pem -out ca-wrong.pem   # wrong content at key path

// after: place the unencrypted private key PEM where the CLI expects it
openssl pkcs8 -topk8 -nocrypt -in ca-encrypted.key -out ca.key
Defensive patterns

Strategy: validation

Validate before calling

import org.bouncycastle.openssl.PEMParser;
import java.io.*;

static boolean isPrivateKeyPem(File keyFile) {
    if (keyFile == null || !keyFile.isFile()) return false;
    try (PEMParser p = new PEMParser(new FileReader(keyFile))) {
        Object obj = p.readObject();
        return obj instanceof java.security.KeyPair
            || obj instanceof org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
    } catch (IOException e) {
        return false;
    }
}
// call before generating: if (!isPrivateKeyPem(Constants.PK_FILE)) throw ...

Type guard

static boolean isPemPrivateKey(Object pemObject) {
    return pemObject instanceof java.security.KeyPair
        || pemObject instanceof org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
}

Try / catch

try {
    PrivateKey key = loadPrivateKey();
} catch (IllegalStateException e) {
    // e.getMessage() names the offending class; check the file content
    throw new IllegalArgumentException(
        "CA key file is not a private key PEM: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Running the CA-signed certificate generation command (caPrivateKey path) when the CA key file at Constants.PK_FILE contains a PEM object of another type — most commonly an X509Certificate instead of the key, an encrypted PEM (PEMEncryptedKeyPair / PEMEncryptedPrivateKey) which parses as neither branch, or a SubjectPublicKeyInfo.

Common situations: Swapped files: user copied the CA certificate (.crt/.pem) over the key file path; a PKCS#8 key protected with a passphrase (encrypted PEM not decryptable here); keys regenerated by another tool in a format PEMParser reads as a non-key object; empty or truncated key file leaving a leftover certificate object.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/eabe9acf96cb833e. Report an issue: GitHub.