dotnet/aspnetcore · error · RuntimeException
'%s' already has a value returning handler. Multiple return
Error message
'%s' already has a value returning handler. Multiple return values are not supported.
What it means
CallbackMap stores handlers per hub method target. When you register an `on` handler whose action returns a value (getHasResult()==true), the map forbids a second value-returning handler for the same target, because the client can only send one result back to the server for a server-to-client invocation.
Source
Thrown at src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/CallbackMap.java:30
class CallbackMap {
private final Map<String, List<InvocationHandler>> handlers = new HashMap<>();
private final ReentrantLock lock = new ReentrantLock();
public InvocationHandler put(String target, Object action, Type... types) {
try {
lock.lock();
InvocationHandler handler = new InvocationHandler(action, types);
if (!handlers.containsKey(target)) {
handlers.put(target, new ArrayList<>());
}
List<InvocationHandler> methodHandlers;
methodHandlers = handlers.get(target);
if (handler.getHasResult()) {
for (InvocationHandler existingHandler : methodHandlers) {
if (existingHandler.getHasResult()) {
throw new RuntimeException(String.format("'%s' already has a value returning handler. Multiple return values are not supported.", target));
}
}
}
methodHandlers = new ArrayList<>(methodHandlers);
methodHandlers.add(handler);
// replace List in handlers map
handlers.remove(target);
handlers.put(target, methodHandlers);
return handler;
} finally {
lock.unlock();
}
}
public List<InvocationHandler> get(String key) {
try {
lock.lock();View on GitHub (pinned to 294cab2f9b)
Solutions
- Keep at most one value-returning handler per method name; remove (hubConnection.remove(name, handler)) before re-registering.
- Use hubConnection.on(...) once during connection setup and dispose handlers on teardown.
- If multiple consumers need the same method, route through a single dispatcher that returns one value.
- Audit registration paths (reconnect callbacks, DI, lifecycle hooks) for accidental double-registration.
Example fix
// before
hubConnection.on("Calc", (int a) -> a + 1, int.class);
hubConnection.on("Calc", (int a) -> a * 2, int.class); // throws
// after
hubConnection.remove("Calc", firstHandler);
hubConnection.on("Calc", (int a) -> a * 2, int.class); Defensive patterns
Strategy: validation
Validate before calling
Set<String> returningTargets = new HashSet<>();
void register(String target, Object action, Type... types) {
InvocationHandler h = new InvocationHandler(action, types);
if (h.getHasResult() && returningTargets.contains(target)) {
throw new IllegalStateException("Returning handler already registered for " + target);
}
if (h.getHasResult()) returningTargets.add(target);
// then hubConnection.on(...)
} Try / catch
try {
hubConnection.on("Method", action, types);
} catch (RuntimeException e) {
if (e.getMessage().contains("already has a value returning handler")) {
hubConnection.remove("Method", previousHandler);
hubConnection.on("Method", action, types);
} else throw e;
} Prevention
- Register value-returning handlers once per method name at connection setup.
- Always remove handlers in teardown before re-registering.
- Centralize registration to avoid duplicate calls across components.
When it happens
Trigger: Calling hubConnection.on("MethodName", actionWithType) twice for the same MethodName where both handlers return a value; or calling on(...).on(...) after removing one but the prior returning handler still lingers.
Common situations: Duplicate registration during a reconnect or re-init, a refactor that registers the same handler in two places, or a handler registered both globally and in a component without cleanup.
Related errors
- Expected either 'error' or 'result' to be provided, but not
- Invocation provides %d argument(s) but target expects %d.
- A valid url is required.
- The HubConnection url must be a valid url.
- There are no callbacks registered for the method '%s'.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/4194c134f659da2f.
Report an issue: GitHub.