dotnet/aspnetcore · error · RuntimeException

Trying to send and message while the connection is not…

Error message

Trying to send and message while the connection is not active.

What it means

sendHubMessageWithLock is the internal dispatch used by the public invoke/send/stream paths after they have built the HubMessage. It re-checks the state under the lock because the state may have transitioned away from CONNECTED between the caller's check and the actual transport.send. The message text contains a typo ('send and message').

Solutions

  1. Retry the invocation after the connection is re-established (subscribe to onReconnected).
  2. Serialize invocations through a single queue drained only when state == CONNECTED so the window cannot open.
  3. Avoid calling stop() concurrently with outstanding invocations - drain them first or let them fail fast.

Example fix

// before
hub.invoke("M").subscribe(...);
// concurrently on another thread:
hub.stop();

// after - stop only after invocations drain
hub.invoke("M").await();
hub.stop().await();
Defensive patterns

Strategy: retry

Try / catch

// This is an internal send; treat any 'connection is not active' failure
// from invoke/send/stream as recoverable.
try {
  hub.invoke("M").await();
} catch (RuntimeException e) {
  if (e.getMessage().contains("connection is not active")) {
    // wait for onReconnected, then retry once
  } else throw e;
}

Prevention

When it happens

Trigger: The connection drops between the outer invoke/send state check and this inner send: a close/transport-error callback fires on another thread and moves the state to DISCONNECTED before sendHubMessageWithLock acquires the lock.

Common situations: High-concurrency invoke during an unstable network; server-initiated close arriving while a burst of invocations is queued; stop() called concurrently with invoke() on another thread.

Related errors


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

Appendix: source

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

            sendInvocationMessage(method, args, invocationId, true);
            return observable.doOnDispose(() -> {
                if (subscriptionCount.decrementAndGet() == 0) {
                    CancelInvocationMessage cancelInvocationMessage = new CancelInvocationMessage(null, invocationId);
                    sendHubMessageWithLock(cancelInvocationMessage);
                    connectionState.tryRemoveInvocation(invocationId);
                    subject.onComplete();
                }
            });
        } finally {
            this.state.unlock();
        }
    }

    private void sendHubMessageWithLock(HubMessage message) {
        this.state.lock();
        try {
            if (this.state.getHubConnectionState() != HubConnectionState.CONNECTED) {
                throw new RuntimeException("Trying to send and message while the connection is not active.");
            }
            ByteBuffer serializedMessage = protocol.writeMessage(message);
            if (message.getMessageType() == HubMessageType.INVOCATION) {
                logger.debug("Sending {} message '{}'.", message.getMessageType().name(), ((InvocationMessage)message).getInvocationId());
            } else  if (message.getMessageType() == HubMessageType.STREAM_INVOCATION) {
                logger.debug("Sending {} message '{}'.", message.getMessageType().name(), ((StreamInvocationMessage)message).getInvocationId());
            } else {
                logger.debug("Sending {} message.", message.getMessageType().name());
            }

            ConnectionState connectionState = this.state.getConnectionStateUnsynchronized(false);
            connectionState.transport.send(serializedMessage).subscribeWith(CompletableSubject.create());
            connectionState.resetKeepAlive();
        } finally {
            this.state.unlock();
        }
    }

View on GitHub (pinned to 3600ca084e)