grpc/grpc-java · error · IOException

ProxySelector returned , which violates the…

Error message

ProxySelector ${proxySelectorClass} returned ${nullOrEmptyList}, which violates the java.net.ProxySelector#select(URI) contract

What it means

gRPC's ProxyDetectorImpl delegates proxy discovery to java.net.ProxySelector.select(URI). The JDK contract requires a non-null, non-empty result; a custom ProxySelector that returns null or an empty list violates this, and gRPC fails the detection with an IOException naming the offending implementation.

Solutions

  1. Fix the custom ProxySelector to return Proxy.NO_PROXY instead of null or an empty list when no proxy applies
  2. Implement select() to always return a list with at least one Proxy (Direct for no proxy)
  3. Handle the IOException from gRPC's proxy detection and fall back to a direct connection
  4. Remove/uninstall the broken ProxySelector (ProxySelector.setDefault) and rely on standard -Dhttps.proxyHost settings

Example fix

// before
public List<Proxy> select(URI uri) {
  if (!"https".equals(uri.getScheme())) return null;
  ...
}
// after
public List<Proxy> select(URI uri) {
  if (!"https".equals(uri.getScheme())) return Collections.singletonList(Proxy.NO_PROXY);
  ...
}
Defensive patterns

Strategy: try-catch

Validate before calling

ProxySelector sel = ProxySelector.getDefault();
List<Proxy> proxies = sel.select(uri);
if (proxies == null || proxies.isEmpty()) {
  // broken selector; restore default or fix before starting gRPC channels
}

Try / catch

try { channel = builder.build(); } catch (IOException e) { if (e.getMessage().contains("violates the java.net.ProxySelector#select(URI) contract")) { ProxySelector.setDefault(null); /* or fix selector */ } else throw e; }

Prevention

When it happens

Trigger: System properties java.net.useSystemProxies or -Dhttp(s).proxyHost with a custom/3rd-party ProxySelector installed via ProxySelector.setDefault that returns null or empty for the gRPC target URI.

Common situations: Corporate environment with a broken custom ProxySelector; custom selector not handling the grpc scheme/URI, returning null instead of Proxy.NO_PROXY (empty list also violates contract; must return Proxy.NO_PROXY for direct).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at core/src/main/java/io/grpc/internal/ProxyDetectorImpl.java:213

    } catch (final URISyntaxException e) {
      log.log(
          Level.WARNING,
          "Failed to construct URI for proxy lookup, proceeding without proxy",
          e);
      return null;
    }

    ProxySelector proxySelector = this.proxySelector.get();
    if (proxySelector == null) {
      log.log(Level.FINE, "proxy selector is null, so continuing without proxy lookup");
      return null;
    }

    List<Proxy> proxies = proxySelector.select(uri);
    // ProxySelector.select(URI) is contractually required to return a non-null, non-empty list.
    // Surface the offending implementation's class name so a broken ProxySelector can be fixed.
    if (proxies == null || proxies.isEmpty()) {
      throw new IOException(
          "ProxySelector " + proxySelector.getClass().getName()
              + " returned " + (proxies == null ? "null" : "an empty list")
              + ", which violates the java.net.ProxySelector#select(URI) contract");
    }
    if (proxies.size() > 1) {
      log.warning("More than 1 proxy detected, gRPC will select the first one");
    }
    Proxy proxy = proxies.get(0);

    if (proxy.type() == Proxy.Type.DIRECT) {
      return null;
    }
    InetSocketAddress proxyAddr = (InetSocketAddress) proxy.address();
    // The prompt string should be the realm as returned by the server.
    // We don't have it because we are avoiding the full handshake.
    String promptString = "";
    PasswordAuthentication auth =
        authenticationProvider.requestPasswordAuthentication(

View on GitHub (pinned to 64daddc1f3)