grpc/grpc-java · error · IllegalArgumentException

'use' parameter must be '%s' but '%s' found. Certificate loa

Error message

'use' parameter must be '%s' but '%s' found. Certificate loading for trust domain '%s' failed.

What it means

SpiffeUtil.checkJwkEntry requires each trust bundle JWK to have 'use' set exactly to the accepted value ("x509-svid"). A missing 'use' or any other value means the key is not declared as an X.509-SVID verification key, so the check fails with an IllegalArgumentException naming the trust domain.

Source

Thrown at core/src/main/java/io/grpc/internal/SpiffeUtil.java:222

    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;
      }
      InputStream stream = new ByteArrayInputStream((CERTIFICATE_PREFIX + rawCerts.get(0) + "\n"
          + CERTIFICATE_SUFFIX)
          .getBytes(StandardCharsets.UTF_8));
      try {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Set "use":"x509-svid" on every JWK in the trust bundle
  2. Use the SPIRE agent's x509 bundle endpoint output, which sets use correctly
  3. Do not mix JWT-SVID keys (use "jwt-svid") into an X.509 trust bundle file

Example fix

// before
{"kty":"RSA","use":"sig","x5c":["..."]}
// after
{"kty":"RSA","use":"x509-svid","x5c":["..."]}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check every JWK's use field
for (Map<String, ?> key : keys) {
  Object use = key.get("use");
  if (!"x509-svid".equals(use)) {
    throw new IllegalStateException("JWK use must be 'x509-svid', got: " + use);
  }
}

Type guard

boolean isX509SvidKey(Map<String, ?> jwk) {
  return "x509-svid".equals(jwk.get("use"));
}

Try / catch

try {
  certs = SpiffeUtil.loadTrustBundleFromFile(bundlePath);
} catch (IllegalArgumentException e) {
  log.error("Trust bundle JWK has wrong 'use' value: " + e.getMessage());
  throw new TrustBundleLoadException(e);
}

Prevention

When it happens

Trigger: Loading a trust bundle whose JWKs omit 'use' or use values like "sig", "jwt-svid", or "enc" instead of "x509-svid", via extractCert during trust bundle loading.

Common situations: Bundles copied from OAuth/OIDC JWKS endpoints where use is "sig"; JWT-SVID bundles mistakenly used for X.509 verification; hand-assembled bundles missing the use field.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/735fd6ce0ba81696. Report an issue: GitHub.