{"record":{"id":"15ba8ddc5499e4d0","repo":"dotnet/aspnetcore","slug":"the-hubconnection-url-must-be-a-valid-url-15ba8d","errorCode":null,"errorMessage":"The HubConnection url must be a valid url.","messagePattern":"The HubConnection url must be a valid url\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java","lineNumber":215,"sourceCode":"     *\n     * @return HubConnection state enum.\n     */\n    public HubConnectionState getConnectionState() {\n        return this.state.getHubConnectionState();\n    }\n\n    // For testing only\n    String getBaseUrl() {\n        return this.baseUrl;\n    }\n\n    /**\n     * Sets a new url for the HubConnection.\n     * @param url The url to connect to.\n     */\n    public void setBaseUrl(String url) {\n        if (url == null || url.isEmpty()) {\n            throw new IllegalArgumentException(\"The HubConnection url must be a valid url.\");\n        }\n\n        if (this.state.getHubConnectionState() != HubConnectionState.DISCONNECTED) {\n            throw new IllegalStateException(\"The HubConnection must be in the disconnected state to change the url.\");\n        }\n\n        this.baseUrl = url;\n    }\n\n    /**\n     * Starts a connection to the server.\n     *\n     * @return A Completable that completes when the connection has been established.\n     */\n    public Completable start() {\n        CompletableSubject localStart = CompletableSubject.create();\n\n        this.state.lock.lock();","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java#L197-L233","documentation":"Thrown by HubConnection.setBaseUrl when the new url is null or empty. setBaseUrl is used to redirect the connection to a different endpoint (e.g. after a negotiate redirect or for sharding) and validates its input the same way the constructor does. Distinct from constructor guard (172) - this fires when changing URL after construction.","triggerScenarios":"Calling hubConnection.setBaseUrl(null) or hubConnection.setBaseUrl(\"\") while the connection is disconnected (the disconnected-state check at 219 runs only after this passes).","commonSituations":"Redirecting to a URL loaded from a response header/config that resolved to null/empty; programmatic redirect logic that computed an empty string; copy/paste left the new URL blank.","solutions":["Validate the new URL is non-null and non-empty before calling setBaseUrl.","Resolve redirect URLs against a base/origin if they are relative; reject empty results explicitly.","Log the candidate URL before setting it so an empty value is visible at the boundary."],"exampleFix":"// before\nString redirect = response.getHeader(\"Location\"); // null\nconn.setBaseUrl(redirect); // throws\n\n// after\nString redirect = response.getHeader(\"Location\");\nif (redirect == null || redirect.trim().isEmpty()) {\n  throw new IllegalStateException(\"Redirect URL missing\");\n}\nconn.setBaseUrl(redirect);","handlingStrategy":"validation","validationCode":"void setUrlSafe(HubConnection conn, String url) {\n  if (url == null || url.isEmpty()) {\n    throw new IllegalArgumentException(\"new url is required\");\n  }\n  conn.setBaseUrl(url);\n}","typeGuard":"boolean isNonEmptyUrl(String url) {\n  return url != null && !url.isEmpty();\n}","tryCatchPattern":"try {\n  conn.setBaseUrl(newUrl);\n} catch (IllegalArgumentException e) {\n  if (\"The HubConnection url must be a valid url.\".equals(e.getMessage())) {\n    // resolve a non-empty url and retry\n  } else throw e;\n}","preventionTips":["Validate the new URL is non-empty before calling setBaseUrl.","Resolve relative redirects against an origin before setting.","Log candidate redirect URLs at the boundary so empty values surface early."],"tags":["signalr","java","argument-validation","url","redirect"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}