dotnet/aspnetcore · error · RuntimeException

There are no callbacks registered for the method

Error message

There are no callbacks registered for the method '%s'.

What it means

Inside the HubConnection binder, getParameterTypes(methodName) is called by the protocol layer to deserialize an inbound server->client InvocationMessage. If handlers were registered for the method name but the list is empty (a registration bug), the binder cannot determine parameter types and throws. A null handler list is handled separately (returns emptyArray with a warning); only a non-null but empty list triggers this throw.

Solutions

  1. Ensure hub.on(method, action) actually adds a non-null action; verify with hub.off() then re-on() if the list may be stale.
  2. After unregistering handlers, call hub.off(method) to fully remove the entry rather than leaving an empty list.
  3. Upgrade the client - this is a defensive throw for an internal invariant; if hit with correct on() usage, file an issue.

Example fix

// before
hub.on("Update", null); // produces empty handler list

// after
hub.on("Update", msg -> { /* handle */ });
// to remove:
hub.remove("Update");
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on a handler, ensure it is actually registered.
// (No public getter exists; track registrations yourself.)
Set<String> registeredMethods = ConcurrentHashMap.newKeySet();
hub.on("Update", msg -> { registeredMethods.add("Update"); /*handle*/ registeredMethods.add("Update"); });
// Server will only invoke methods present in this set with a non-empty handler.

Try / catch

// The throw surfaces during message binding. If hit, the inbound message is dropped.
// Log it and verify your on() registrations.
hub.onClosed(ex -> {
  if (ex != null && ex.getMessage().contains("no callbacks registered")) {
    log.error("Handler missing for server-invoked method; re-register and reconnect");
  }
});

Prevention

When it happens

Trigger: Server invokes a client method for which hub.on(method, ...) was called with an action that got removed/never set, leaving an empty List<InvocationHandler> in the handlers map. The binder then cannot read argument types for deserialization.

Common situations: A handler was registered then unregistered but the empty list entry was not removed from the map; misuse of the on() API leaving a placeholder; reflection-based handler registration that produced zero handlers.

Related errors


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

Appendix: source

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

        public Type getReturnType(String invocationId) {
            InvocationRequest irq = getInvocation(invocationId);
            if (irq == null) {
                return null;
            }

            return irq.getReturnType();
        }

        @Override
        public List<Type> getParameterTypes(String methodName) {
            List<InvocationHandler> handlers = connection.handlers.get(methodName);
            if (handlers == null) {
                logger.warn("Failed to find handler for '{}' method.", methodName);
                return emptyArray;
            }

            if (handlers.isEmpty()) {
                throw new RuntimeException(String.format("There are no callbacks registered for the method '%s'.", methodName));
            }

            return handlers.get(0).getTypes();
        }

        private void errorHandshake(Exception error) {
            lock.lock();
            try {
                // If onError is called on a completed subject the global error handler is called
                if (!(handshakeResponseSubject.hasComplete() || handshakeResponseSubject.hasThrowable())) {
                    handshakeResponseSubject.onError(error);
                }
            } finally {
                lock.unlock();
            }
        }
    }

View on GitHub (pinned to 3600ca084e)