OrchardCMS/OrchardCore · error · Error
HttpConnection.stopConnection
Error message
HttpConnection.stopConnection(${error}) was called while the connection is still in the connecting state. What it means
HttpConnection.stopConnection is an internal lifecycle method that must only run on a connection that is connected/disconnecting/disconnected. If it is invoked while the connection is still in the Connecting state, the client throws this Error because that indicates a transport calling onclose during startup — an internal state-machine invariant violation.
Solutions
- Await connection.start() before calling connection.stop(), and serialize start/stop calls (e.g. a mutex/promise chain).
- Catch the error around start() and retry with backoff instead of calling stop() concurrently.
- Check negotiate endpoint reachability/auth — a failing handshake often triggers the transport onclose during Connecting.
- Upgrade @microsoft/signalr — several early transport-close races were fixed in later versions.
Example fix
// before connection.stop(); await connection.start(); // after await connection.stop(); await connection.start(); // or guard: // if (connection.state === signalR.HubConnectionState.Disconnected) await connection.start();
Defensive patterns
Strategy: try-catch
Validate before calling
if (connection.state !== signalR.HubConnectionState.Disconnected) {
throw new Error('Cannot start: connection is not in Disconnected state');
} Type guard
const canStart = (c) => c.state === signalR.HubConnectionState.Disconnected;
Try / catch
try {
if (connection.state === signalR.HubConnectionState.Disconnected) {
await connection.start();
}
} catch (e) {
if (String(e.message).includes('stopConnection') || String(e.message).includes('connecting state')) {
// wait for settle, then retry with backoff
}
} Prevention
- Serialize start/stop calls through a single promise queue.
- Always await start() before issuing stop().
- Use withAutomaticReconnect instead of manual stop/start cycles.
- Upgrade @microsoft/signalr to pick up lifecycle race fixes.
When it happens
Trigger: A transport's onclose fires during the start() sequence (e.g. WebSocket fails immediately, SSE errors during connection) before stopConnectionMoveTo/transition to Connected completes; race between start() and stop(); manual call to internal stopConnection API while connecting.
Common situations: Rapid connection.start()/stop() calls racing each other; network drops exactly during handshake; buggy custom transport; server rejecting the connection mid-handshake (auth failure, 401/404 negotiate).
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- The ' ' argument is required.
- The ' ' argument should not be empty.
- Unknown value: .
- could not find global
- The HubConnection must be in the Disconnected or…
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/7a9d9e8c6dcba155.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore.Modules/OrchardCore.SignalR/wwwroot/Scripts/signalr.js:3088
}
}
}
_isITransport(transport) {
return transport && typeof (transport) === "object" && "connect" in transport;
}
_stopConnection(error) {
this._logger.log(LogLevel.Debug, `HttpConnection.stopConnection(${error}) called while in state ${this._connectionState}.`);
this.transport = undefined;
// If we have a stopError, it takes precedence over the error from the transport
error = this._stopError || error;
this._stopError = undefined;
if (this._connectionState === "Disconnected" /* ConnectionState.Disconnected */) {
this._logger.log(LogLevel.Debug, `Call to HttpConnection.stopConnection(${error}) was ignored because the connection is already in the disconnected state.`);
return;
}
if (this._connectionState === "Connecting" /* ConnectionState.Connecting */) {
this._logger.log(LogLevel.Warning, `Call to HttpConnection.stopConnection(${error}) was ignored because the connection is still in the connecting state.`);
throw new Error(`HttpConnection.stopConnection(${error}) was called while the connection is still in the connecting state.`);
}
if (this._connectionState === "Disconnecting" /* ConnectionState.Disconnecting */) {
// A call to stop() induced this call to stopConnection and needs to be completed.
// Any stop() awaiters will be scheduled to continue after the onclose callback fires.
this._stopPromiseResolver();
}
if (error) {
this._logger.log(LogLevel.Error, `Connection disconnected with error '${error}'.`);
}
else {
this._logger.log(LogLevel.Information, "Connection disconnected.");
}
if (this._sendQueue) {
this._sendQueue.stop().catch((e) => {
this._logger.log(LogLevel.Error, `TransportSendQueue.stop() threw error '${e}'.`);
});
this._sendQueue = undefined;
}View on GitHub (pinned to 4306c0717f)