jwtk/jjwt · error · IllegalArgumentException

Unable to access X509Certificate encoded bytes necessary to

Error message

Unable to access X509Certificate encoded bytes necessary to perform DER Base64-encoding. Certificate: {${cert}}. Cause: ${e.getMessage()}

What it means

JwtX509StringConverter.applyTo encodes an X509Certificate to a Base64 DER string for the x5c header. If cert.getEncoded() throws CertificateEncodingException (the certificate provider cannot produce its DER encoding), the converter throws IllegalArgumentException with this message, embedding the certificate and cause.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/JwtX509StringConverter.java:46

public class JwtX509StringConverter implements Converter<X509Certificate, CharSequence> {

    public static final JwtX509StringConverter INSTANCE = new JwtX509StringConverter();

    // Returns a Base64 encoded (NOT Base64Url encoded) string of the cert's encoded byte array per
    // https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.6
    // https://www.rfc-editor.org/rfc/rfc7516.html#section-4.1.8
    // https://www.rfc-editor.org/rfc/rfc7517.html#section-4.7
    @Override
    public String applyTo(X509Certificate cert) {
        Assert.notNull(cert, "X509Certificate cannot be null.");
        byte[] der = Bytes.EMPTY;
        try {
            try {
                der = cert.getEncoded();
            } catch (CertificateEncodingException e) {
                String msg = "Unable to access X509Certificate encoded bytes necessary to perform DER " +
                        "Base64-encoding. Certificate: {" + cert + "}. Cause: " + e.getMessage();
                throw new IllegalArgumentException(msg, e);
            }
            if (Bytes.isEmpty(der)) {
                String msg = "X509Certificate encoded bytes cannot be null or empty.  Certificate: {" + cert + "}.";
                throw new IllegalArgumentException(msg);
            }
            return Encoders.BASE64.encode(der);
        } finally {
            Bytes.clear(der);
        }
    }

    // visible for testing
    protected X509Certificate toCert(final byte[] der) throws SecurityException {
        return new JcaTemplate("X.509").generateX509Certificate(der);
    }

    @Override
    public X509Certificate applyFrom(CharSequence s) {

View on GitHub (pinned to fb71496164)

Solutions

  1. Check the wrapped cause for the provider-level encoding failure and re-load the certificate from its original PEM/DER bytes via CertificateFactory.
  2. Ensure the certificate was parsed by CertificateFactory.getInstance("X.509") from valid encoded bytes.
  3. Add/remove the BouncyCastle provider consistently so the cert's provider can encode it.
  4. Re-generate the certificate if the underlying object is corrupt.

Example fix

// before
X509Certificate cert = (X509Certificate) customProviderObject; // exotic impl, getEncoded fails

// after
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(pemBytes));
Defensive patterns

Strategy: try-catch

Validate before calling

boolean hasEncoding(X509Certificate cert) {
    try { return cert.getEncoded() != null && cert.getEncoded().length > 0; }
    catch (CertificateEncodingException e) { return false; }
}

Try / catch

try {
    String x5c = converter.applyTo(cert);
} catch (IllegalArgumentException e) {
    if (e.getCause() instanceof CertificateEncodingException) {
        // reload cert from PEM/DER via CertificateFactory
    } else throw e;
}

Prevention

When it happens

Trigger: Building a JWS/JWT with an x5c (X.509 certificate chain) header whose certificate's getEncoded() fails, typically because the underlying provider cannot encode the certificate format.

Common situations: Certificates loaded from non-standard providers or exotic formats (e.g. a certificate implementation backed by an unsupported provider); corrupted or partially parsed certificate objects; provider mismatch after moving keys between JVM security providers (BouncyCastle vs default SUN).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/6bd564daf11133a9. Report an issue: GitHub.