dotnet/aspnetcore · error · RuntimeException
The HubConnection failed to transition from the '%s' state t
Error message
The HubConnection failed to transition from the '%s' state to the '%s' state because it was actually in the '%s' state.
What it means
Thrown by the internal changeState(from, to) guard when the connection's actual HubConnectionState does not equal the expected 'from' state. It signals a state-machine inconsistency, almost always caused by concurrent or re-entrant start()/stop()/automatic-reconnect operations racing on the same HubConnection. The start() error handler at HubConnection.java:350-353 intentionally swallows it, so it normally surfaces only outside that guarded path.
Source
Thrown at src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java:1717
}
return this.state;
} finally {
this.lock.unlock();
}
}
public HubConnectionState getHubConnectionState() {
return this.hubConnectionState;
}
public void changeState(HubConnectionState from, HubConnectionState to) {
this.lock.lock();
try {
logger.debug("The HubConnection is attempting to transition from the {} state to the {} state.", from, to);
if (this.hubConnectionState != from) {
logger.debug("The HubConnection failed to transition from the {} state to the {} state because it was actually in the {} state.",
from, to, this.hubConnectionState);
throw new RuntimeException(String.format("The HubConnection failed to transition from the '%s' state to the '%s' state because it was actually in the '%s' state.",
from, to, this.hubConnectionState));
}
this.hubConnectionState = to;
} finally {
this.lock.unlock();
}
}
public void changeState(HubConnectionState to) {
this.lock.lock();
try {
logger.debug("The HubConnection is transitioning from the {} state to the {} state.", this.hubConnectionState, to);
this.hubConnectionState = to;
} finally {
this.lock.unlock();
}
}View on GitHub (pinned to 294cab2f9b)
Solutions
- Serialize lifecycle calls: block on the previous start()/stop() Completable before issuing the next.
- Guard with hubConnection.getHubConnectionState() before calling start()/stop().
- Coordinate/disable withAutomaticReconnect when you manually manage connection lifecycle.
- Avoid issuing start() on an instance that is already CONNECTING/CONNECTED.
Example fix
// before
hubConnection.start().subscribe(() -> {}, e -> {});
hubConnection.start().subscribe(() -> {}, e -> {}); // races
// after
hubConnection.start().blockingAwait();
// only start again after stop().blockingAwait() Defensive patterns
Strategy: validation
Validate before calling
// Java - check state before lifecycle calls
if (hubConnection.getHubConnectionState() == HubConnectionState.DISCONNECTED) {
hubConnection.start().blockingAwait();
} Try / catch
// Wrap a contested lifecycle op; this error is usually swallowed internally,
// so prefer preventing the race over catching it.
try {
hubConnection.start().blockingAwait();
} catch (RuntimeException ex) {
// log and reconcile state before retrying
} Prevention
- Never call start() concurrently with another start()/stop()/reconnect on the same instance.
- Always block on the previous start()/stop() Completable before issuing the next.
- If using withAutomaticReconnect, do not also manually start/stop in a way that overlaps it.
When it happens
Trigger: Calling start() while a previous start() is still mid-handshake; calling stop() during the CONNECTING->CONNECTED transition at line 324; withAutomaticReconnect racing a manual stop(); invoking start() twice in quick succession without waiting on the first Completable.
Common situations: Background reconnect logic overlapping a manual reconnect; a UI 'Connect' button that allows double-tap; withAutomaticReconnect enabled combined with manual stop/start cycling; reusing a HubConnection instance across rapid lifecycle changes.
Related errors
- HubConnection trying to negotiate when not in the CONNECTING
- Invocation Id is already used
- The HubConnection must be in the disconnected state to chang
- The 'send' method cannot be called if the connection is not
- The 'invoke' method cannot be called if the connection is no
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/5a7267bac6679f28.
Report an issue: GitHub.