grpc/grpc-java · error · UnsupportedOperationException

TLS should be configured by the servlet container

Error message

TLS should be configured by the servlet container

What it means

ServletServerBuilder.useTransportSecurity is intentionally unsupported: in the servlet gRPC transport, TLS termination happens in the servlet container (e.g. Tomcat, Jetty), not in the gRPC server builder. Calling this method always throws UnsupportedOperationException to make that explicit.

Solutions

  1. Remove the useTransportSecurity call and configure HTTPS/TLS on the servlet container instead
  2. Deploy the servlet behind a TLS-terminating reverse proxy (nginx, load balancer) and keep the servlet endpoint plain HTTP
  3. Revert to a transport like NettyServerBuilder if in-process TLS configuration is required

Example fix

// before
serverBuilder.useTransportSecurity(new File("cert.pem"), new File("key.pem")); // throws
// after
// configure TLS in web.xml / container config; no code needed in ServletServerBuilder
Defensive patterns

Strategy: fallback

Validate before calling

if (builder instanceof ServletServerBuilder) { /* configure TLS in servlet container instead */ }

Try / catch

try { builder.useTransportSecurity(cert, key); } catch (UnsupportedOperationException e) { log.info("Configure TLS in the servlet container"); }

Prevention

When it happens

Trigger: Calling useTransportSecurity(File certChain, File privateKey) on a ServletServerBuilder when attempting to configure certificates the way one would with NettyServerBuilder.

Common situations: Porting server code from NettyServerBuilder to ServletServerBuilder and copying over TLS configuration lines; expecting the builder API to be uniform across transports.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at servlet/src/main/java/io/grpc/servlet/ServletServerBuilder.java:183

    checkNotNull(streamTracerFactories, "streamTracerFactories");
    this.streamTracerFactories = streamTracerFactories;
    internalServer = new InternalServerImpl();
    return internalServer;
  }

  @Internal
  @Override
  protected ServerBuilder<?> delegate() {
    return serverImplBuilder;
  }

  /**
   * Throws {@code UnsupportedOperationException}. TLS should be configured by the servlet
   * container.
   */
  @Override
  public ServletServerBuilder useTransportSecurity(File certChain, File privateKey) {
    throw new UnsupportedOperationException("TLS should be configured by the servlet container");
  }

  /**
   * Specifies how to determine gRPC method name from servlet request.
   *
   * <p>The default strategy is using {@link HttpServletRequest#getRequestURI()} without the leading
   * slash.</p>
   */
  public ServletServerBuilder methodNameResolver(
      Function<HttpServletRequest, String> methodResolver) {
    this.methodNameResolver = checkNotNull(methodResolver);
    return this;
  }

  @Override
  public ServletServerBuilder maxInboundMessageSize(int bytes) {
    checkArgument(bytes >= 0, "bytes must be >= 0");
    maxInboundMessageSize = bytes;

View on GitHub (pinned to 64daddc1f3)