{"record":{"id":"4194c134f659da2f","repo":"dotnet/aspnetcore","slug":"s-already-has-a-value-returning-handler-multip","errorCode":null,"errorMessage":"'%s' already has a value returning handler. Multiple return values are not supported.","messagePattern":"'(.+?)' already has a value returning handler\\. Multiple return values are not supported\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/CallbackMap.java","lineNumber":30,"sourceCode":"\nclass CallbackMap {\n    private final Map<String, List<InvocationHandler>> handlers = new HashMap<>();\n    private final ReentrantLock lock = new ReentrantLock();\n\n    public InvocationHandler put(String target, Object action, Type... types) {\n        try {\n            lock.lock();\n            InvocationHandler handler = new InvocationHandler(action, types);\n            if (!handlers.containsKey(target)) {\n                handlers.put(target, new ArrayList<>());\n            }\n\n            List<InvocationHandler> methodHandlers;\n            methodHandlers = handlers.get(target);\n            if (handler.getHasResult()) {\n                for (InvocationHandler existingHandler : methodHandlers) {\n                    if (existingHandler.getHasResult()) {\n                        throw new RuntimeException(String.format(\"'%s' already has a value returning handler. Multiple return values are not supported.\", target));\n                    }\n                }\n            }\n            methodHandlers = new ArrayList<>(methodHandlers);\n            methodHandlers.add(handler);\n\n            // replace List in handlers map\n            handlers.remove(target);\n            handlers.put(target, methodHandlers);\n            return handler;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public List<InvocationHandler> get(String key) {\n        try {\n            lock.lock();","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/CallbackMap.java#L12-L48","documentation":"Thrown by CallbackMap.put when registering a second handler that returns a value (getHasResult()==true) for the same server-to-client method target. The Java client lets multiple handlers subscribe to one target (broadcast style), but only one of them may produce a return value, because the server expects a single completion per invocation id.","triggerScenarios":"Calling hubConnection.on('Send', msg -> ...) twice where the lambda returns a value (or registering via a Type that makes the handler a 'result' handler); calling .map('Send', ...) twice; mixing .on and .map for the same target where both produce results.","commonSituations":"Refactor duplicated an .on registration without removing the old one; a base class and subclass both subscribe to the same method with a return type; using .map (single-result) for a target already handled by another .map.","solutions":["Call hubConnection.remove('Send') before re-registering, or ensure only one result-producing handler exists per target.","Use hubConnection.on(...) for fire-and-forget subscriptions that do not return a value; reserve .map(...) for the single handler that must return a result.","Audit registrations in startup/reconnect code to confirm they are idempotent (remove before add)."],"exampleFix":"// before\nhubConnection.map(\"GetTime\", () -> Instant.now());\nhubConnection.map(\"GetTime\", () -> Instant.now()); // throws\n\n// after\nhubConnection.remove(\"GetTime\");\nhubConnection.map(\"GetTime\", () -> Instant.now());","handlingStrategy":"validation","validationCode":"void ensureSingleResultHandler(HubConnection conn, String target, Action1<Object> handler) {\n  conn.remove(target); // idempotent: clear any prior result handler\n}\n\n// before re-registering:\nconn.remove(\"GetTime\");\nconn.map(\"GetTime\", () -> Instant.now());","typeGuard":"// Java has no first-class type guards; emulate with a registry check.\nboolean hasResultHandler(CallbackMap map, String target) {\n  return map.get(target).stream().anyMatch(InvocationHandler::getHasResult);\n}","tryCatchPattern":"try {\n  conn.map(target, handler);\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"already has a value returning handler\")) {\n    conn.remove(target);\n    conn.map(target, handler); // now safe\n  } else throw e;\n}","preventionTips":["Call conn.remove(target) before re-registering a result handler.","Reserve .map(...) for the single result-producing handler; use .on(...) for broadcast subscriptions.","Make registration code idempotent in reconnect/startup paths."],"tags":["signalr","java","handler-registration","callback","invocation"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}