grpc/grpc-java · error · IllegalArgumentException
Certificate can't be parsed. Certificate loading for trust d
Error message
Certificate can't be parsed. Certificate loading for trust domain '%s' failed.
What it means
SpiffeUtil.extractCert decodes the base64 x5c certificate of each JWK and parses it as X.509 via CertificateFactory. If parsing throws CertificateException (corrupt DER, wrong encoding, non-certificate bytes), it is wrapped in this IllegalArgumentException with the trust domain name.
Source
Thrown at core/src/main/java/io/grpc/internal/SpiffeUtil.java:247
String trustDomainName) {
List<X509Certificate> result = new ArrayList<>();
for (Map<String, ?> keyNode : keysNode) {
checkJwkEntry(keyNode, trustDomainName);
List<String> rawCerts = JsonUtil.getListOfStrings(keyNode, "x5c");
if (rawCerts == null || rawCerts.isEmpty()) {
continue;
}
InputStream stream = new ByteArrayInputStream((CERTIFICATE_PREFIX + rawCerts.get(0) + "\n"
+ CERTIFICATE_SUFFIX)
.getBytes(StandardCharsets.UTF_8));
try {
Collection<? extends Certificate> certs = CertificateFactory.getInstance("X509")
.generateCertificates(stream);
X509Certificate[] certsArray = certs.toArray(new X509Certificate[0]);
assert certsArray.length == 1;
result.add(certsArray[0]);
} catch (CertificateException e) {
throw new IllegalArgumentException(String.format("Certificate can't be parsed. Certificate "
+ "loading for trust domain '%s' failed.", trustDomainName), e);
}
}
return result;
}
/**
* Represents a SPIFFE ID as defined in the SPIFFE standard.
* @see <a href="https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md">Standard</a>
*/
public static class SpiffeId {
private final String trustDomain;
private final String path;
private SpiffeId(String trustDomain, String path) {
this.trustDomain = trustDomain;
this.path = path;View on GitHub (pinned to 64daddc1f3)
Solutions
- Ensure x5c contains base64 DER only: strip PEM headers/footers and keep the raw base64 body
- Verify the cert independently: openssl x509 -inform DER -in cert.der -text
- Regenerate the bundle from SPIRE rather than hand-copying certificates
- Confirm the file was not truncated or line-wrapped by editors/transfer tools
Example fix
// before "x5c": ["-----BEGIN CERTIFICATE-----\nMIIB...\n-----END CERTIFICATE-----"] // after "x5c": ["MIIBdzCCAV2gAwIBAgIUP...base64-DER-only..."]
Defensive patterns
Strategy: try-catch
Validate before calling
// Decode and sanity-check x5c before loading
byte[] der = java.util.Base64.getMimeDecoder().decode((String) jwk.get("x5c").get(0));
try {
new javax.crypto.spec.X509EncodedKeySpec(der); // basic length sanity
java.security.cert.CertificateFactory.getInstance("X509")
.generateCertificate(new java.io.ByteArrayInputStream(der));
} catch (Exception e) {
throw new IllegalStateException("x5c entry is not a parseable X.509 cert", e);
} Try / catch
try {
certs = SpiffeUtil.loadTrustBundleFromFile(bundlePath);
} catch (IllegalArgumentException e) {
log.error("Unparseable certificate in trust bundle: " + e.getMessage(), e.getCause());
throw new TrustBundleLoadException(e);
} Prevention
- Put base64 DER only in x5c — strip PEM headers/footers and newlines
- openssl-verify each cert before bundling
- Avoid manual copy/paste of certificates; script bundle generation
When it happens
Trigger: A trust bundle JWK's x5c entry contains bytes that are not a valid X.509 certificate — truncated base64, a PEM header pasted into x5c, or an unrelated key blob — during loadTrustBundleFromFile.
Common situations: Manually assembled bundles where a PEM string (-----BEGIN CERTIFICATE-----) was placed in x5c instead of the base64 DER body; damaged files transferred via copy/paste or mis-encoded downloads.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Multiple URI SAN values found in the leaf cert.
- SPIFFE Trust Bundle should be a JSON object. Found: ${type}
- 'kty' parameter must be one of %s but '%s' found. Certificat
- 'kid' parameter must not be set. Certificate loading for tru
- 'use' parameter must be '%s' but '%s' found. Certificate loa
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/c944fd16e984984e.
Report an issue: GitHub.