{"record":{"id":"b58774a3776c2c84","repo":"grpc/grpc-java","slug":"kty-parameter-must-be-one-of-s-but-s-found","errorCode":null,"errorMessage":"'kty' parameter must be one of %s but '%s' found. Certificate loading for trust domain '%s' failed.","messagePattern":"'kty' parameter must be one of (.+?) but '(.+?)' found\\. Certificate loading for trust domain '(.+?)' failed\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/SpiffeUtil.java","lineNumber":210,"sourceCode":"    String json = new String(Files.toByteArray(file), StandardCharsets.UTF_8);\n    Object jsonObject = JsonParser.parse(json);\n    if (!(jsonObject instanceof Map)) {\n      throw new IllegalArgumentException(\n          \"SPIFFE Trust Bundle should be a JSON object. Found: \"\n              + (jsonObject == null ? null : jsonObject.getClass()));\n    }\n    @SuppressWarnings(\"unchecked\")\n    Map<String, ?> root = (Map<String, ?>)jsonObject;\n    Map<String, ?> trustDomainsNode = JsonUtil.getObject(root, \"trust_domains\");\n    checkNotNull(trustDomainsNode, \"Mandatory trust_domains element is missing\");\n    checkArgument(trustDomainsNode.size() > 0, \"Mandatory trust_domains element is missing\");\n    return trustDomainsNode;\n  }\n\n  private static void checkJwkEntry(Map<String, ?> jwkNode, String trustDomainName) {\n    String kty = JsonUtil.getString(jwkNode, \"kty\");\n    if (kty == null || !KTY_PARAMETER_VALUES.contains(kty)) {\n      throw new IllegalArgumentException(\n          String.format(\n              \"'kty' parameter must be one of %s but '%s' \"\n                  + \"found. Certificate loading for trust domain '%s' failed.\",\n              KTY_PARAMETER_VALUES, kty, trustDomainName));\n    }\n    if (jwkNode.containsKey(\"kid\")) {\n      throw new IllegalArgumentException(String.format(\"'kid' parameter must not be set. \"\n              + \"Certificate loading for trust domain '%s' failed.\", trustDomainName));\n    }\n    String use = JsonUtil.getString(jwkNode, \"use\");\n    if (use == null || !use.equals(USE_PARAMETER_VALUE)) {\n      throw new IllegalArgumentException(String.format(\"'use' parameter must be '%s' but '%s' \"\n              + \"found. Certificate loading for trust domain '%s' failed.\", USE_PARAMETER_VALUE,\n          use, trustDomainName));\n    }\n  }\n\n  private static List<X509Certificate> extractCert(List<Map<String, ?>> keysNode,","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/SpiffeUtil.java#L192-L228","documentation":"SpiffeUtil.checkJwkEntry validates each JWK in a SPIFFE trust bundle. The 'kty' (key type) parameter must be one of the accepted values (e.g. RSA or EC); a missing or unrecognized kty makes the key unusable for X.509-SVID verification, so an IllegalArgumentException naming the trust domain is thrown.","triggerScenarios":"Loading a trust bundle whose JWK entry lacks 'kty' or has a kty outside KTY_PARAMETER_VALUES (e.g. \"oct\" for symmetric keys, or a lowercase/misspelled value like \"rsa\"), via extractCert during bundle loading.","commonSituations":"Hand-built bundles with keys exported from JWKS endpoints that include oct keys; manually trimmed JWKs missing required fields; typos like \"RSA \" or \"RS256\" mistakenly placed in kty.","solutions":["Set kty to a supported value — \"RSA\" or \"EC\" — matching the actual key material","Remove oct (symmetric) keys from the trust bundle; SPIFFE X.509 bundles contain only public asymmetric keys","Fix casing/spelling: kty values are exact-case per RFC 7517 (\"RSA\", not \"rsa\" or \"RS256\")","Regenerate the bundle from SPIRE (spire-agent api fetch x509-bundle) rather than hand-editing"],"exampleFix":"// before\n{\"use\":\"x509-svid\",\"kty\":\"rsa\",\"n\":\"...\"}\n// after\n{\"use\":\"x509-svid\",\"kty\":\"RSA\",\"n\":\"...\"}","handlingStrategy":"validation","validationCode":"// Pre-check every JWK's kty\nfor (Map<String, ?> key : keys) {\n  String kty = (String) key.get(\"kty\");\n  if (!\"RSA\".equals(kty) && !\"EC\".equals(kty)) {\n    throw new IllegalStateException(\"JWK kty must be RSA or EC, got: \" + kty);\n  }\n}","typeGuard":"boolean hasSupportedKty(Map<String, ?> jwk) {\n  Object kty = jwk.get(\"kty\");\n  return \"RSA\".equals(kty) || \"EC\".equals(kty);\n}","tryCatchPattern":"try {\n  certs = SpiffeUtil.loadTrustBundleFromFile(bundlePath);\n} catch (IllegalArgumentException e) {\n  log.error(\"Trust bundle JWK rejected: \" + e.getMessage());\n  throw new TrustBundleLoadException(e);\n}","preventionTips":["Exclude symmetric (oct) keys from trust bundles","Keep exact-case kty values per RFC 7517","Regenerate bundles with SPIRE tooling instead of hand-editing"],"tags":["grpc","spiffe","jwk","trust-bundle","validation"],"backgroundTag":"invalid-enum-value","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}