grpc/grpc-java · error · IllegalArgumentException

TLS version %d is not supported.

Error message

TLS version %d is not supported.

What it means

convertTlsProtocolVersion maps S2A handshaker protobuf TLSVersion enum values to Java TLS protocol-name strings. The default branch throws this IllegalArgumentException when the proto enum carries a value outside the supported set (TLS 1.0/1.1/1.2), typically because the S2A handshaker server sent an enum value this client build does not know (e.g. TLS 1.3 in an older client).

Source

Thrown at s2a/src/main/java/io/grpc/s2a/internal/handshaker/ProtoUtil.java:46

   *
   * @param tlsVersion the {@link TLSVersion} object to be converted.
   * @return a {@link String} representation of the TLS version.
   * @throws IllegalArgumentException if the {@code tlsVersion} is not one of
   *     the supported TLS versions.
   */
  @VisibleForTesting
  static String convertTlsProtocolVersion(TLSVersion tlsVersion) {
    switch (tlsVersion) {
      case TLS_VERSION_1_3:
        return "TLSv1.3";
      case TLS_VERSION_1_2:
        return "TLSv1.2";
      case TLS_VERSION_1_1:
        return "TLSv1.1";
      case TLS_VERSION_1_0:
        return "TLSv1";
      default:
        throw new IllegalArgumentException(
            String.format("TLS version %d is not supported.", tlsVersion.getNumber()));
    }
  }

  /**
   * Builds a set of strings representing all {@link TLSVersion}s between {@code minTlsVersion} and
   * {@code maxTlsVersion}.
   */
  static ImmutableSet<String> buildTlsProtocolVersionSet(
      TLSVersion minTlsVersion, TLSVersion maxTlsVersion) {
    ImmutableSet.Builder<String> tlsVersions = ImmutableSet.<String>builder();
    for (TLSVersion tlsVersion : TLSVersion.values()) {
      int versionNumber;
      try {
        versionNumber = tlsVersion.getNumber();
      } catch (IllegalArgumentException e) {
        continue;
      }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Upgrade the gRPC s2a client/handshaker library to a version whose proto and mapping include the TLS version S2A returns.
  2. Constrain the S2A policy's min/max TLS versions to 1.0–1.2 (ideally just TLS 1.2) until versions are aligned.
  3. Check the handshaker proto: ensure both sides are generated from the same tls.proto version so enum numbers match.
  4. Log tlsVersion.getNumber() on failure to identify the offending enum value and confirm the diagnosis.

Example fix

// before (older client)
min_tls_version: TLS_VERSION_1_3
// after
min_tls_version: TLS_VERSION_1_2  // or upgrade client library to support TLS 1.3
Defensive patterns

Strategy: validation

Validate before calling

static void checkSupportedTlsVersion(TLSVersion v) {
  switch (v) {
    case TLS_VERSION_1_0:
    case TLS_VERSION_1_1:
    case TLS_VERSION_1_2:
      return;
    default:
      throw new IllegalArgumentException("TLS version " + v.getNumber() + " unsupported by client");
  }
}

Prevention

When it happens

Trigger: Calling buildTlsProtocolVersionSet (invoked during S2A channel setup) with min/max TLS versions where a version is TLS_VERSION_UNSPECIFIED, out-of-range, or a newer enum constant (e.g. TLS_VERSION_1_3) unrecognized by the mapped switch in this client version.

Common situations: S2A server upgraded to support TLS 1.3 while the gRPC s2a client library predates that enum value; misconfigured S2A policy returning TLS_VERSION_UNSPECIFIED; version skew between handshaker proto files.

Understand the failure class

Related errors


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