{"record":{"id":"fb1e6039e26e0807","repo":"OpenFeign/feign","slug":"failed-to-open-graphql-subscription-to-request-u","errorCode":null,"errorMessage":"failed to open GraphQL subscription to ${request.url()}","messagePattern":"failed to open GraphQL subscription to (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"graphql/src/main/java/feign/graphql/GraphqlSubscriptionClient.java","lineNumber":128,"sourceCode":"\n    var builder = httpClient.newWebSocketBuilder().subprotocols(\"graphql-transport-ws\");\n    if (options != null && options.connectTimeoutMillis() > 0) {\n      builder.connectTimeout(Duration.ofMillis(options.connectTimeoutMillis()));\n    }\n    request\n        .headers()\n        .forEach(\n            (name, values) -> {\n              if (isForwardable(name)) {\n                values.forEach(value -> builder.header(name, value));\n              }\n            });\n\n    try {\n      subscription.attach(builder.buildAsync(webSocketUri(request.url()), subscription).join());\n    } catch (CompletionException e) {\n      var cause = e.getCause() == null ? e : e.getCause();\n      throw new IOException(\"failed to open GraphQL subscription to \" + request.url(), cause);\n    }\n\n    // 204 keeps feign's logger from draining and replacing the body, which would drop the live\n    // subscription. Nothing here ever crosses the wire.\n    return Response.builder()\n        .status(HttpURLConnection.HTTP_NO_CONTENT)\n        .reason(\"Subscribed\")\n        .request(request)\n        .headers(Collections.emptyMap())\n        .body(subscription)\n        .build();\n  }\n\n  /** Headers the JDK WebSocket handshake rejects or manages itself. */\n  private static boolean isForwardable(String header) {\n    var name = header.toLowerCase(Locale.ROOT);\n    return !name.equals(\"connection\")\n        && !name.equals(\"upgrade\")","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/OpenFeign/feign/blob/e2a1e27560a1e68840c34f031afca88b36096e30/graphql/src/main/java/feign/graphql/GraphqlSubscriptionClient.java#L110-L146","documentation":"GraphqlSubscriptionClient opens a WebSocket for a GraphQL subscription via java.net.http.WebSocket. If the asynchronous attach/handshake fails (unreachable server, TLS error, rejected upgrade, timeout), the CompletionException is unwrapped and rethrown as an IOException naming the request URL.","triggerScenarios":"subscribe()/execute() called and subscription.attach(...).join() completes exceptionally: server does not accept WebSocket upgrade at the URL, network/TLS failure, wrong scheme (http instead of ws), or the join() future times out.","commonSituations":"GraphQL endpoint does not support subscriptions, a reverse proxy blocks WebSocket upgrades, the URL points at a plain HTTP route, firewall blocks ws/wss traffic, server down.","solutions":["Verify the server supports GraphQL subscriptions (WebSocket upgrade) at that URL and the scheme is ws:// or wss://","Check proxies/load balancers allow the WebSocket Upgrade headers","Inspect e.getCause() on the IOException for the underlying CompletionException/ConnectException","Confirm network reachability (connectivity test to host:port) and TLS certificate validity"],"exampleFix":"// before\nGraphQL client = GraphQL.builder()\n    .decoder(decoder).target(\"https://api.example.com/graphql\").build();\nclient.subscriptions().execute(subscriptionRequest);\n// after: ensure the URL/endpoint supports ws upgrades and handle the IOException\ntry {\n  client.subscriptions().execute(subscriptionRequest);\n} catch (IOException e) {\n  log.error(\"subscription setup failed: \" + e.getCause(), e);\n}","handlingStrategy":"retry","validationCode":"URI uri = URI.create(request.url());\nif (!uri.getScheme().matches(\"wss?\"))\n  throw new IllegalArgumentException(\"subscription URL must use ws/wss: \" + uri);","typeGuard":null,"tryCatchPattern":"try {\n  client.subscriptions().execute(req);\n} catch (IOException e) {\n  if (e.getCause() instanceof CompletionException || e.getMessage().contains(\"failed to open\")) {\n    // retry with backoff or surface a connectivity problem\n    retryWithBackoff(req);\n  } else throw e;\n}","preventionTips":["Confirm the endpoint supports WebSocket subscriptions before enabling them","Use wss:// with valid certificates in production","Monitor network/proxy configurations that block WebSocket upgrades","Add health checks against the subscription endpoint"],"tags":["graphql","websocket","subscription","network"],"backgroundTag":"connection-refused","analyzedSha":"e2a1e27560a1e68840c34f031afca88b36096e30","analyzedAt":"2026-09-10T12:37:37.238Z","contentChangedAt":"2026-09-10T12:37:37.238Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}