dotnet/aspnetcore · error · RuntimeException
There are no callbacks registered for the method '%s'.
Error message
There are no callbacks registered for the method '%s'.
What it means
A RuntimeException thrown by ConnectionState.getParameterTypes when the handler list for a method name exists but is empty. getParameterTypes is called by the protocol during parseMessages to bind incoming invocation arguments; an empty handler list means the method name resolved but carries no callbacks/parameter types, making argument binding impossible.
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 294cab2f9b)
Solutions
- Ensure at least one handler is registered for methods the server invokes on the client; re-register with connection.on(...) before the server can call them.
- Avoid disposing the last handler for a method the server still invokes; either keep a handler or coordinate with the server to stop invoking.
- If seen transiently during handler swap, register the new handler before disposing the old one.
Example fix
// before: dispose removes the only handler, server then invokes the method
Subscription sub = connection.on("Notify", (String m) -> { ... }, String.class);
sub.dispose(); // now handler list is empty
// server invokes "Notify" -> getParameterTypes throws
// after: register the new handler before disposing the old
Subscription sub2 = connection.on("Notify", (String m) -> { /* new */ }, String.class);
sub.dispose(); // list still has sub2 Defensive patterns
Strategy: validation
Validate before calling
// Ensure handlers are registered before the server can invoke them, and don't dispose
// the last handler for a server-invoked method.
connection.on("Notify", (String m) -> { ... }, String.class);
// Keep this registration alive while the server may invoke "Notify". Try / catch
// This error is thrown inside parseMessages and surfaces as a connection error.
// Subscribe to onClosed to detect it; the fix is to keep handlers registered.
connection.onClosed(ex -> {
if (ex != null && ex.getMessage().contains("no callbacks registered")) {
logger.error("Server invoked a method with no handlers; re-register handlers");
}
}); Prevention
- Register handlers for all server-to-client methods before calling start().
- When swapping handlers, register the new one before disposing the old.
- Avoid disposing the last handler for a method the server still invokes.
- Keep a registry of required handlers and assert it's populated at startup.
When it happens
Trigger: During parseMessages, binder.getParameterTypes(target) is called for an incoming InvocationMessage. connection.handlers.get(methodName) returns a non-null but empty list (e.g. all handlers were removed but the list entry remains, or an internal inconsistency), triggering the throw at line 1647.
Common situations: A handler was registered then removed via Subscription.dispose() leaving an empty list in the map (depends on CallbackMap implementation). The server invokes a client method right at the moment handlers are being removed/added (race). Internal CallbackMap inconsistency. The %s placeholder names the affected method to aid diagnosis.
Related errors
- Invocation provides %d argument(s) but target expects %d.
- '%s' already has a value returning handler. Multiple return
- Expected either 'error' or 'result' to be provided, but not
- Message is incomplete.
- The message type %s is not supported yet.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/1ee93f27a3686dda.
Report an issue: GitHub.