{"record":{"id":"21633ee56d4b3ea0","repo":"grpc/grpc-java","slug":"proxyselector-proxyselectorclass-returned-nul","errorCode":null,"errorMessage":"ProxySelector ${proxySelectorClass} returned ${nullOrEmptyList}, which violates the java.net.ProxySelector#select(URI) contract","messagePattern":"ProxySelector (.+?) returned (.+?), which violates the java\\.net\\.ProxySelector#select\\(URI\\) contract","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/ProxyDetectorImpl.java","lineNumber":213,"sourceCode":"    } catch (final URISyntaxException e) {\n      log.log(\n          Level.WARNING,\n          \"Failed to construct URI for proxy lookup, proceeding without proxy\",\n          e);\n      return null;\n    }\n\n    ProxySelector proxySelector = this.proxySelector.get();\n    if (proxySelector == null) {\n      log.log(Level.FINE, \"proxy selector is null, so continuing without proxy lookup\");\n      return null;\n    }\n\n    List<Proxy> proxies = proxySelector.select(uri);\n    // ProxySelector.select(URI) is contractually required to return a non-null, non-empty list.\n    // Surface the offending implementation's class name so a broken ProxySelector can be fixed.\n    if (proxies == null || proxies.isEmpty()) {\n      throw new IOException(\n          \"ProxySelector \" + proxySelector.getClass().getName()\n              + \" returned \" + (proxies == null ? \"null\" : \"an empty list\")\n              + \", which violates the java.net.ProxySelector#select(URI) contract\");\n    }\n    if (proxies.size() > 1) {\n      log.warning(\"More than 1 proxy detected, gRPC will select the first one\");\n    }\n    Proxy proxy = proxies.get(0);\n\n    if (proxy.type() == Proxy.Type.DIRECT) {\n      return null;\n    }\n    InetSocketAddress proxyAddr = (InetSocketAddress) proxy.address();\n    // The prompt string should be the realm as returned by the server.\n    // We don't have it because we are avoiding the full handshake.\n    String promptString = \"\";\n    PasswordAuthentication auth =\n        authenticationProvider.requestPasswordAuthentication(","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/ProxyDetectorImpl.java#L195-L231","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Fix the custom ProxySelector to return Proxy.NO_PROXY instead of null or an empty list when no proxy applies","Implement select() to always return a list with at least one Proxy (Direct for no proxy)","Handle the IOException from gRPC's proxy detection and fall back to a direct connection","Remove/uninstall the broken ProxySelector (ProxySelector.setDefault) and rely on standard -Dhttps.proxyHost settings"],"exampleFix":"// before\npublic List<Proxy> select(URI uri) {\n  if (!\"https\".equals(uri.getScheme())) return null;\n  ...\n}\n// after\npublic List<Proxy> select(URI uri) {\n  if (!\"https\".equals(uri.getScheme())) return Collections.singletonList(Proxy.NO_PROXY);\n  ...\n}","handlingStrategy":"try-catch","validationCode":"ProxySelector sel = ProxySelector.getDefault();\nList<Proxy> proxies = sel.select(uri);\nif (proxies == null || proxies.isEmpty()) {\n  // broken selector; restore default or fix before starting gRPC channels\n}","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["Custom ProxySelectors must return Proxy.NO_PROXY, never null or empty lists","Test your ProxySelector with all URI schemes your app dials","Prefer standard -Dhttps.proxyHost configuration over custom selectors"],"tags":["grpc","proxy","io","jdk-contract"],"backgroundTag":"invalid-argument-value","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}