{"record":{"id":"1cf8c08b74c62329","repo":"dotnet/aspnetcore","slug":"trying-to-send-and-message-while-the-connection-is","errorCode":null,"errorMessage":"Trying to send and message while the connection is not active.","messagePattern":"Trying to send and message while the connection is not active\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java","lineNumber":828,"sourceCode":"            sendInvocationMessage(method, args, invocationId, true);\n            return observable.doOnDispose(() -> {\n                if (subscriptionCount.decrementAndGet() == 0) {\n                    CancelInvocationMessage cancelInvocationMessage = new CancelInvocationMessage(null, invocationId);\n                    sendHubMessageWithLock(cancelInvocationMessage);\n                    connectionState.tryRemoveInvocation(invocationId);\n                    subject.onComplete();\n                }\n            });\n        } finally {\n            this.state.unlock();\n        }\n    }\n\n    private void sendHubMessageWithLock(HubMessage message) {\n        this.state.lock();\n        try {\n            if (this.state.getHubConnectionState() != HubConnectionState.CONNECTED) {\n                throw new RuntimeException(\"Trying to send and message while the connection is not active.\");\n            }\n            ByteBuffer serializedMessage = protocol.writeMessage(message);\n            if (message.getMessageType() == HubMessageType.INVOCATION) {\n                logger.debug(\"Sending {} message '{}'.\", message.getMessageType().name(), ((InvocationMessage)message).getInvocationId());\n            } else  if (message.getMessageType() == HubMessageType.STREAM_INVOCATION) {\n                logger.debug(\"Sending {} message '{}'.\", message.getMessageType().name(), ((StreamInvocationMessage)message).getInvocationId());\n            } else {\n                logger.debug(\"Sending {} message.\", message.getMessageType().name());\n            }\n\n            ConnectionState connectionState = this.state.getConnectionStateUnsynchronized(false);\n            connectionState.transport.send(serializedMessage).subscribeWith(CompletableSubject.create());\n            connectionState.resetKeepAlive();\n        } finally {\n            this.state.unlock();\n        }\n    }\n","sourceCodeStart":810,"sourceCodeEnd":846,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java#L810-L846","documentation":"A RuntimeException thrown by the internal sendHubMessageWithLock helper when the HubConnection is not CONNECTED at the moment a hub message (ping, invocation, stream item, close, cancel, completion) is about to be written. This is an internal guard beneath the public send/invoke/stream APIs and also covers messages produced by the ping timer and by upload-stream forwarding. The message text contains a typo ('send and message') but the intent is the standard 'not active' guard.","triggerScenarios":"Reached when sendHubMessageWithLock is invoked while state != CONNECTED: e.g. the ping timer fires after disconnect, an upload-stream's onNext races with stop(), or send/invoke/stream call paths reach here after the public guard already threw (defensive). Also when onClosed-triggered CloseMessage send is attempted mid-teardown.","commonSituations":"The keep-alive ping timer fires concurrently with stop() and attempts to send a Ping after state moved to DISCONNECTED. An Observable-based upload stream emits an item after the connection dropped. Internal cleanup paths sending CloseMessage during teardown.","solutions":["Ensure stop() fully completes before disposing resources or triggering further sends.","If seen from the ping timer, verify there is no race between stop() and the timer (this is largely internal; report if reproducible in normal usage).","Dispose upload-stream Observables when the connection closes so they stop emitting into a dead connection.","Avoid calling connection methods after onClosed fires."],"exampleFix":"// before: upload stream keeps emitting after disconnect\nObservable<Data> src = hotObservable;\nconnection.send(\"Upload\", src);\n// src keeps emitting after connection.stop() -> sendHubMessageWithLock throws\n\n// after: dispose the source on close\nconnection.onClosed(ex -> srcSubscription.dispose());","handlingStrategy":"validation","validationCode":"// Internal guard; the practical user-side guard is to avoid emitting into a closed connection.\n// Dispose upload-stream sources on close.\nconnection.onClosed(ex -> uploadStreamSubscription.dispose());","typeGuard":"boolean connectionActive = connection.getConnectionState() == HubConnectionState.CONNECTED;","tryCatchPattern":"// This error is internal and surfaces through transport/onError paths. Catch at the\n// subscription boundary:\nsomeObservable.subscribe(item -> {\n    if (connection.getConnectionState() == HubConnectionState.CONNECTED) {\n        connection.send(\"Upload\", item);\n    }\n}, error -> { /* log */ });","preventionTips":["Dispose upload-stream Observables when the connection closes.","Do not call HubConnection methods from onClosed except to schedule reconnect.","Gate any callback that may fire post-disconnect on a state check.","If reproducible from the ping timer under normal usage, report as a library bug."],"tags":["signalr","java","lifecycle","internal","concurrency","send"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}