{"record":{"id":"7a9d9e8c6dcba155","repo":"OrchardCMS/OrchardCore","slug":"httpconnection-stopconnection-error-was-called-while-the","errorCode":null,"errorMessage":"HttpConnection.stopConnection(${error}) was called while the connection is still in the connecting state.","messagePattern":"HttpConnection\\.stopConnection\\((.+?)\\) was called while the connection is still in the connecting state\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/OrchardCore.Modules/OrchardCore.SignalR/wwwroot/Scripts/signalr.js","lineNumber":3088,"sourceCode":"            }\n        }\n    }\n    _isITransport(transport) {\n        return transport && typeof (transport) === \"object\" && \"connect\" in transport;\n    }\n    _stopConnection(error) {\n        this._logger.log(LogLevel.Debug, `HttpConnection.stopConnection(${error}) called while in state ${this._connectionState}.`);\n        this.transport = undefined;\n        // If we have a stopError, it takes precedence over the error from the transport\n        error = this._stopError || error;\n        this._stopError = undefined;\n        if (this._connectionState === \"Disconnected\" /* ConnectionState.Disconnected */) {\n            this._logger.log(LogLevel.Debug, `Call to HttpConnection.stopConnection(${error}) was ignored because the connection is already in the disconnected state.`);\n            return;\n        }\n        if (this._connectionState === \"Connecting\" /* ConnectionState.Connecting */) {\n            this._logger.log(LogLevel.Warning, `Call to HttpConnection.stopConnection(${error}) was ignored because the connection is still in the connecting state.`);\n            throw new Error(`HttpConnection.stopConnection(${error}) was called while the connection is still in the connecting state.`);\n        }\n        if (this._connectionState === \"Disconnecting\" /* ConnectionState.Disconnecting */) {\n            // A call to stop() induced this call to stopConnection and needs to be completed.\n            // Any stop() awaiters will be scheduled to continue after the onclose callback fires.\n            this._stopPromiseResolver();\n        }\n        if (error) {\n            this._logger.log(LogLevel.Error, `Connection disconnected with error '${error}'.`);\n        }\n        else {\n            this._logger.log(LogLevel.Information, \"Connection disconnected.\");\n        }\n        if (this._sendQueue) {\n            this._sendQueue.stop().catch((e) => {\n                this._logger.log(LogLevel.Error, `TransportSendQueue.stop() threw error '${e}'.`);\n            });\n            this._sendQueue = undefined;\n        }","sourceCodeStart":3070,"sourceCodeEnd":3106,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore.Modules/OrchardCore.SignalR/wwwroot/Scripts/signalr.js#L3070-L3106","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nconnection.stop();\nawait connection.start();\n// after\nawait connection.stop();\nawait connection.start();\n// or guard:\n// if (connection.state === signalR.HubConnectionState.Disconnected) await connection.start();","handlingStrategy":"try-catch","validationCode":"if (connection.state !== signalR.HubConnectionState.Disconnected) {\n  throw new Error('Cannot start: connection is not in Disconnected state');\n}","typeGuard":"const canStart = (c) => c.state === signalR.HubConnectionState.Disconnected;","tryCatchPattern":"try {\n  if (connection.state === signalR.HubConnectionState.Disconnected) {\n    await connection.start();\n  }\n} catch (e) {\n  if (String(e.message).includes('stopConnection') || String(e.message).includes('connecting state')) {\n    // wait for settle, then retry with backoff\n  }\n}","preventionTips":["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."],"tags":["signalr","javascript","state-machine","race-condition"],"backgroundTag":"invalid-state-transition","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}