quarkusio/quarkus · error · RuntimeException
Failure to create a private key
Error message
Failure to create a private key
What it means
LetsEncryptHelpers.getPrivateKey() base64-decodes the key material and reconstructs a PrivateKey via KeyFactory with a PKCS8EncodedKeySpec, choosing RSA unless the algorithm is explicitly EC. Any decoding or key-generation failure is wrapped in this RuntimeException. It means the stored ACME account/order private key could not be parsed.
Source
Thrown at extensions/tls-registry/cli/src/main/java/io/quarkus/tls/cli/letsencrypt/LetsEncryptHelpers.java:270
private static X509Certificate getCertificate(String encodedCert) {
try {
byte[] encodedBytes = Base64.getDecoder().decode(encodedCert);
return (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(encodedBytes));
} catch (Exception ex) {
throw new RuntimeException("Failure to create a certificate", ex);
}
}
private static PrivateKey getPrivateKey(String encodedKey, String keyAlgorithm) {
try {
KeyFactory f = KeyFactory.getInstance((keyAlgorithm == null || "RSA".equals(keyAlgorithm) ? "RSA" : "EC"));
byte[] encodedBytes = Base64.getDecoder().decode(encodedKey);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encodedBytes);
return f.generatePrivate(spec);
} catch (Exception ex) {
throw new RuntimeException("Failure to create a private key", ex);
}
}
public static void renewCertificate(AcmeClient acmeClient,
File letsEncryptPath,
boolean staging,
String domain,
File certChainPemLoc,
File privateKeyPemLoc,
String acmeServerUrl,
String acmeStagingServerUrl) {
LOGGER.infof("\uD83D\uDD35 Renewing %s ACME certificate chain and private key",
(staging ? "staging" : "production"));
issueCertificate(acmeClient, letsEncryptPath, staging, domain, certChainPemLoc, privateKeyPemLoc,
acmeServerUrl, acmeStagingServerUrl);
}
public static void deactivateAccount(AcmeClient acmeClient, File letsEncryptPath, boolean staging,View on GitHub (pinned to e1c734241f)
Solutions
- Regenerate the key by deleting the letsencrypt directory and letting the tooling issue a new order/key
- Convert PKCS#1 keys to PKCS#8 (openssl pkcs8 -topk8) before storing
- Ensure keyAlgorithm matches the actual key ('RSA' or 'EC'); pass null for RSA default
- Verify the base64 payload has no PEM headers or whitespace before calling
Example fix
// before PrivateKey key = LetsEncryptHelpers.getPrivateKey(pkcs1KeyBody, "EC"); // after // convert to PKCS#8 first: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key.pkcs8.pem PrivateKey key = LetsEncryptHelpers.getPrivateKey(pkcs8KeyBody, "EC");
Defensive patterns
Strategy: validation
Validate before calling
static boolean isParseablePkcs8Key(String b64, String alg) {
try {
byte[] der = Base64.getDecoder().decode(b64.replaceAll("-----[A-Z ]+-----|\\s", ""));
KeyFactory f = KeyFactory.getInstance(alg == null || "RSA".equals(alg) ? "RSA" : "EC");
f.generatePrivate(new PKCS8EncodedKeySpec(der));
return true;
} catch (Exception e) { return false;
}
} Type guard
if (keyAlg != null && !keyAlg.equals("RSA") && !keyAlg.equals("EC")) throw new IllegalArgumentException("Unsupported keyAlgorithm: " + keyAlg); Try / catch
try {
PrivateKey key = LetsEncryptHelpers.getPrivateKey(encoded, alg);
} catch (RuntimeException e) {
LOGGER.error("Stored private key unreadable (wrong format?); regenerate key", e);
deleteKeyAndRenew();
} Prevention
- Always store keys in PKCS#8 (convert PKCS#1 with openssl pkcs8 -topk8)
- Keep keyAlgorithm config in sync with the actual key type
- Never hand-edit or truncate key files; regenerate via the tooling
- Back up the key directory so corruption can be recovered from a known-good copy
When it happens
Trigger: getPrivateKey(encodedKey, keyAlgorithm) throws when the string is not valid base64, the decoded bytes are not a PKCS#8 structure, or the key algorithm mismatch (e.g. an EC key parsed with the RSA KeyFactory, or a non-RSA/non-EC keyAlgorithm passed).
Common situations: Key file regenerated by another tool in PKCS#1 ('BEGIN RSA PRIVATE KEY') instead of PKCS#8, key truncated or corrupted on disk, keyAlgorithm config changed to EC while the stored key is RSA.
Related errors
- X.509-SVID response from SPIRE agent contains an invalid pri
- Failure to create a certificate
- Expected a base64 encoded byte array, got: ${text}
- X.509-SVID response from SPIRE agent has empty private key
- The file <path> does not contain a private key <type>
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/9d51ad05ec43931c.
Report an issue: GitHub.