apereo/cas · error · BeanCreationException
Could not decode provided KeyFile
Error message
Could not decode provided KeyFile
What it means
getPrivateKey() decodes the resource referenced by privateKeyResource into a PrivateKey using KeySupport.decodePrivateKey with the configured password. If the stream cannot be read or the key cannot be decoded (wrong format, wrong or missing password, unsupported algorithm), bean creation fails with BeanCreationException('Could not decode provided KeyFile <resource>', cause). This is the private-key analogue of the certificate decode errors.
Solutions
- Verify the key file exists and is readable at the path in the message (ls -l; cat the header to confirm it is a PRIVATE KEY block).
- If the key is encrypted, set the matching private-key-password property; if no password is intended, decrypt it: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key-pkcs8.pem.
- Convert the key to PKCS#8 PEM, the most widely decodable form: openssl pkcs8 -topk8 -in idp_rsa.key -out idp_pkcs8.key.
- Confirm the file actually contains a private key, not a certificate or public key; regenerate/export the key if truncated or corrupt.
Example fix
# before: encrypted or PKCS#1 key with no password configured -> decode fails cas.authn.saml.idp.credential.private-key=file:/etc/cas/idp-encrypted.key # after: unencrypted PKCS#8 key (convert once with openssl pkcs8 -topk8 -nocrypt) cas.authn.saml.idp.credential.private-key=file:/etc/cas/idp-pkcs8.key
Defensive patterns
Strategy: validation
Validate before calling
// pre-check the private key decodes with the configured password
try (var is = privateKeyResource.getInputStream()) {
KeySupport.decodePrivateKey(is, privateKeyPassword);
} catch (Exception e) {
throw new IllegalStateException("Private key undecodable (format or password wrong): " + privateKeyResource, e);
} Try / catch
try {
credentialFactory.getObject();
} catch (BeanCreationException e) {
if (e.getMessage().startsWith("Could not decode provided KeyFile")) {
// cause is usually BadPaddingException/InvalidKeyException => wrong password/format
logger.error("Check private-key format (use PKCS#8) and privateKeyPassword", e.getCause());
}
throw e;
} Prevention
- Standardize on unencrypted PKCS#8 PEM (openssl pkcs8 -topk8) for private keys in CAS config.
- If the key is encrypted, always set privateKeyPassword and manage it via environment variables/vault, not plaintext config.
- Verify the file starts with '-----BEGIN PRIVATE KEY' (or 'ENCRYPTED PRIVATE KEY') not a certificate or public key.
- Check permissions and existence of the key file in the container entrypoint before CAS starts.
When it happens
Trigger: privateKeyResource is set, but its InputStream throws on read, or KeySupport.decodePrivateKey(is, getPrivateKeyPassword()) throws — e.g. PKCS#8 vs PKCS#1 mismatch, encrypted key with wrong or null password, garbage or truncated key file — inside getPrivateKey().
Common situations: Passing an encrypted PEM key without setting privateKeyPassword (or with the wrong one); providing a raw PKCS#1 'BEGIN RSA PRIVATE KEY' where PKCS#8 is expected; key file missing due to an unmounted volume or wrong path; pasting a public key or certificate into the key file; key truncated or corrupted during transfer.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Public and private keys do not match
- Configuration element indicated an entityCertificate, but…
- Could not decode provided Entity Certificate file
- Could not decode provided CertificateFile:
- Unable to locate signing credentials
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/e0b22990ea8c92df.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-saml-core-api/src/main/java/org/apereo/cas/support/saml/util/credential/BasicX509CredentialFactoryBean.java:157
val certificates = new LazyList<X509Certificate>();
for (val r : certificateResources) {
try (val is = r.getInputStream()) {
certificates.addAll(X509Support.decodeCertificates(is));
} catch (final Exception e) {
throw new BeanCreationException("Could not decode provided CertificateFile: " + r.getDescription(), e);
}
}
return certificates;
}
private PrivateKey getPrivateKey() {
if (null == privateKeyResource) {
return null;
}
try (val is = privateKeyResource.getInputStream()) {
return KeySupport.decodePrivateKey(is, getPrivateKeyPassword());
} catch (final Exception e) {
throw new BeanCreationException("Could not decode provided KeyFile " + privateKeyResource.getDescription(), e);
}
}
@Override
public boolean isSingleton() {
return true;
}
private List<X509CRL> getCRLs() {
if (null == crlResources) {
return null;
}
val crls = new LazyList<X509CRL>();
for (val crl : crlResources) {
try (val is = crl.getInputStream()) {
crls.addAll(X509Support.decodeCRLs(is));
} catch (final Exception e) {
throw new BeanCreationException("Could not decode provided CRL file " + crl.getDescription(), e);View on GitHub (pinned to e7288fc434)