dotnet/aspnetcore · error · IllegalStateException

The HubConnection must be in the disconnected state to…

Error message

The HubConnection must be in the disconnected state to change the url.

What it means

Thrown by HubConnection.setBaseUrl when the connection is not in the DISCONNECTED state. Changing the base URL while connected would corrupt in-flight invocations and transport state, so the client forbids it. The check runs after the null/empty URL check (175).

Solutions

  1. Always stop() the connection and await its completion before calling setBaseUrl.
  2. Gate the redirect logic: if (conn.getConnectionState() == HubConnectionState.DISCONNECTED) conn.setBaseUrl(newUrl); else queue and apply after stop.
  3. For server-driven redirects, rely on the built-in negotiate redirect handling rather than setBaseUrl during an active connection.

Example fix

// before
conn.start().blockingAwait();
conn.setBaseUrl(newUrl); // connected -> throws

// after
conn.stop().blockingAwait();
conn.setBaseUrl(newUrl);
conn.start().blockingAwait();
Defensive patterns

Strategy: validation

Validate before calling

void relocate(HubConnection conn, String newUrl) {
  if (conn.getConnectionState() != HubConnectionState.DISCONNECTED) {
    conn.stop().blockingAwait();
  }
  conn.setBaseUrl(newUrl);
}

Type guard

boolean isDisconnected(HubConnection conn) {
  return conn.getConnectionState() == HubConnectionState.DISCONNECTED;
}

Try / catch

try {
  conn.setBaseUrl(newUrl);
} catch (IllegalStateException e) {
  if ("The HubConnection must be in the disconnected state to change the url.".equals(e.getMessage())) {
    conn.stop().blockingAwait();
    conn.setBaseUrl(newUrl);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling hubConnection.setBaseUrl(newUrl) after start() has connected (or while connecting/reconnecting) and before stop() completes. HubConnectionState.DISCONNECTED is required.

Common situations: Redirect/relocate logic triggered by a server message while the connection is still live; calling setBaseUrl in an onConnected handler; reconnect logic that races and runs setBaseUrl before the previous connection fully stopped.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/47753ddc86ba07c6. Report an issue: GitHub.

Appendix: source

Thrown at src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java:219

        return this.state.getHubConnectionState();
    }

    // For testing only
    String getBaseUrl() {
        return this.baseUrl;
    }

    /**
     * Sets a new url for the HubConnection.
     * @param url The url to connect to.
     */
    public void setBaseUrl(String url) {
        if (url == null || url.isEmpty()) {
            throw new IllegalArgumentException("The HubConnection url must be a valid url.");
        }

        if (this.state.getHubConnectionState() != HubConnectionState.DISCONNECTED) {
            throw new IllegalStateException("The HubConnection must be in the disconnected state to change the url.");
        }

        this.baseUrl = url;
    }

    /**
     * Starts a connection to the server.
     *
     * @return A Completable that completes when the connection has been established.
     */
    public Completable start() {
        CompletableSubject localStart = CompletableSubject.create();

        this.state.lock.lock();
        try {
            if (this.state.getHubConnectionState() != HubConnectionState.DISCONNECTED) {
                logger.debug("The connection is in the '{}' state. Waiting for in-progress start to complete or completing this start immediately.", this.state.getHubConnectionState());
                return this.state.getConnectionStateUnsynchronized(false).startTask;

View on GitHub (pinned to 3600ca084e)