quarkusio/quarkus · error · IllegalStateException

The file does not contain a private key

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.

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.

Appendix: 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)