grpc/grpc-java · error · IllegalArgumentException
'kid' parameter must not be set. Certificate loading for…
Error message
'kid' parameter must not be set. Certificate loading for trust domain '%s' failed.
What it means
Per the SPIFFE X.509 bundle spec, JWK entries must not carry a 'kid' (key ID) parameter, since bundle keys are identified by their SPIFFE ID and x5c chain. SpiffeUtil.checkJwkEntry rejects any JWK containing 'kid' with an IllegalArgumentException naming the trust domain.
Solutions
- Remove the "kid" field from each JWK in the trust bundle file
- Obtain a spec-compliant bundle from your SPIRE agent instead of converting an IdP JWKS
- Validate bundle keys against the SPIFFE X.509 bundle format (kty, use=x509-svid, x5c; no kid)
Example fix
// before
{"kty":"RSA","use":"x509-svid","kid":"key-1","x5c":["..."]}
// after
{"kty":"RSA","use":"x509-svid","x5c":["..."]} Defensive patterns
Strategy: validation
Validate before calling
// Strip/verify no kid fields before loading
for (Map<String, ?> key : keys) {
if (key.containsKey("kid")) {
throw new IllegalStateException("JWK must not contain 'kid' (SPIFFE X.509 bundle spec)");
}
} Type guard
boolean kidFree(Map<String, ?> jwk) {
return !jwk.containsKey("kid");
} Try / catch
try {
certs = SpiffeUtil.loadTrustBundleFromFile(bundlePath);
} catch (IllegalArgumentException e) {
log.error("Trust bundle JWK has disallowed 'kid': " + e.getMessage());
throw new TrustBundleLoadException(e);
} Prevention
- Don't reuse OIDC/OAuth JWKS files as SPIFFE X.509 trust bundles
- Validate bundles against the SPIFFE X.509 bundle spec in CI
- Use spire-agent bundle output, which omits kid
When it happens
Trigger: Loading a trust bundle whose keys include a "kid" field — commonly keys copied from a generic OIDC/OAuth JWKS endpoint where kid is standard — via extractCert during bundle loading.
Common situations: Reusing JWKS from an identity provider's /.well-known/jwks.json as a SPIFFE trust bundle; SPIFFE-compliant bundles produced by some tooling that adds kid by default.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- 'kty' parameter must be one of
- 'use' parameter must be
- Certificate can't be parsed. Certificate loading for trust…
- SPIFFE Trust Bundle should be a JSON object. Found
- Multiple URI SAN values found in the leaf cert.
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/ecf297e92a1123af.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/io/grpc/internal/SpiffeUtil.java:217
@SuppressWarnings("unchecked")
Map<String, ?> root = (Map<String, ?>)jsonObject;
Map<String, ?> trustDomainsNode = JsonUtil.getObject(root, "trust_domains");
checkNotNull(trustDomainsNode, "Mandatory trust_domains element is missing");
checkArgument(trustDomainsNode.size() > 0, "Mandatory trust_domains element is missing");
return trustDomainsNode;
}
private static void checkJwkEntry(Map<String, ?> jwkNode, String trustDomainName) {
String kty = JsonUtil.getString(jwkNode, "kty");
if (kty == null || !KTY_PARAMETER_VALUES.contains(kty)) {
throw new IllegalArgumentException(
String.format(
"'kty' parameter must be one of %s but '%s' "
+ "found. Certificate loading for trust domain '%s' failed.",
KTY_PARAMETER_VALUES, kty, trustDomainName));
}
if (jwkNode.containsKey("kid")) {
throw new IllegalArgumentException(String.format("'kid' parameter must not be set. "
+ "Certificate loading for trust domain '%s' failed.", trustDomainName));
}
String use = JsonUtil.getString(jwkNode, "use");
if (use == null || !use.equals(USE_PARAMETER_VALUE)) {
throw new IllegalArgumentException(String.format("'use' parameter must be '%s' but '%s' "
+ "found. Certificate loading for trust domain '%s' failed.", USE_PARAMETER_VALUE,
use, trustDomainName));
}
}
private static List<X509Certificate> extractCert(List<Map<String, ?>> keysNode,
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;View on GitHub (pinned to 64daddc1f3)