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
- 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
- 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
- Restore the correct key file (re-export from your keystore or regenerate the CA if lost, then re-issue certificates)
- 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
- Keep CA certificate and CA key files in clearly named separate files (ca.crt vs ca.key) and never overwrite one with the other
- Store unencrypted PKCS#8 PEM keys for automated tooling; decrypt passphrase-protected keys before use
- Validate PEM file headers (grep "BEGIN PRIVATE KEY") before handing a file to the generator
- After regenerating or exporting CA material, re-run a content check before issuing certificates
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
- Invalid PEM file: No PEM content found.
- Unable to decrypt the key file: + config.key()
- Alias '${alias}' not found in JKS key store (private key not
- Alias '${alias}' not found in key store (private key not fou
- Alias '${alias}' not found in P12 key store (private key not
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/eabe9acf96cb833e.
Report an issue: GitHub.