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

  1. 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).
  2. 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.
  3. Convert the key to PKCS#8 PEM, the most widely decodable form: openssl pkcs8 -topk8 -in idp_rsa.key -out idp_pkcs8.key.
  4. 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

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


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)