{"record":{"id":"388d46be9d13dcb2","repo":"dotnet/aspnetcore","slug":"invocation-id-is-already-used","errorCode":null,"errorMessage":"Invocation Id is already used","messagePattern":"Invocation Id is already used","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java","lineNumber":1437,"sourceCode":"                for (String key : keys) {\n                    if (ex == null) {\n                        pendingInvocations.get(key).cancel();\n                    } else {\n                        pendingInvocations.get(key).fail(ex);\n                    }\n                }\n\n                pendingInvocations.clear();\n            } finally {\n                lock.unlock();\n            }\n        }\n\n        public void addInvocation(InvocationRequest irq) {\n            lock.lock();\n            try {\n                if (pendingInvocations.containsKey(irq.getInvocationId())) {\n                    throw new IllegalStateException(\"Invocation Id is already used\");\n                } else {\n                    pendingInvocations.put(irq.getInvocationId(), irq);\n                }\n            } finally {\n                lock.unlock();\n            }\n        }\n\n        public InvocationRequest getInvocation(String id) {\n            lock.lock();\n            try {\n                return pendingInvocations.get(id);\n            } finally {\n                lock.unlock();\n            }\n        }\n\n        public InvocationRequest tryRemoveInvocation(String id) {","sourceCodeStart":1419,"sourceCodeEnd":1455,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/SignalR/clients/java/signalr/core/src/main/java/com/microsoft/signalr/HubConnection.java#L1419-L1455","documentation":"An IllegalStateException thrown by ConnectionState.addInvocation when an InvocationRequest with the same invocationId already exists in pendingInvocations. Invocation IDs are generated monotonically via AtomicInteger (getNextInvocationId), so a duplicate under normal single-connection usage is an internal invariant violation indicating the ID generator wrapped or state corrupted.","triggerScenarios":"addInvocation(irq) is called with an id already present in pendingInvocations. In practice this requires the nextId AtomicInteger to produce a value that collides with a still-pending request, which should not happen in correct single-connection operation. Could be triggered by manual id injection in tests or by reusing a HubConnection's internal ConnectionState across logical connections.","commonSituations":"Test code that manually constructs InvocationRequest objects and calls addInvocation with hardcoded ids. A long-lived connection whose integer ID counter is theoretically approaching limits (unlikely). Concurrent invoke/stream calls racing through getNextInvocationId in a way that, combined with a bug, reuses an id. Generally an internal/library bug if seen in production.","solutions":["If reproduced in test code, stop manually setting invocation IDs; let getNextInvocationId generate them.","In production, this indicates a library-level issue; report with a repro and the connection lifecycle trace.","Restart the HubConnection (stop + start) to reset the ID counter and clear pendingInvocations."],"exampleFix":"// before (test): manual duplicate id\nString id = \"1\";\nconnectionState.addInvocation(new InvocationRequest(null, id));\nconnectionState.addInvocation(new InvocationRequest(null, id)); // throws\n\n// after: let the connection generate unique ids\nString id = connectionState.getNextInvocationId();\nconnectionState.addInvocation(new InvocationRequest(null, id));","handlingStrategy":"try-catch","validationCode":"// No public pre-check; this is an internal invariant. The practical guard is to never\n// manually inject invocation IDs and to restart the connection if it occurs.\nif (connection.getConnectionState() != HubConnectionState.CONNECTED) {\n    // don't invoke; avoids internal state corruption\n}","typeGuard":null,"tryCatchPattern":"try {\n    connection.invoke(\"method\").blockingAwait();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Invocation Id is already used\")) {\n        // internal ID collision; restart the connection to reset state\n        connection.stop().blockingAwait();\n        connection.start().blockingAwait();\n    } else { throw e; }\n}","preventionTips":["Never manually construct InvocationRequest with hardcoded IDs in production code.","If the error recurs, restart the HubConnection to reset the ID counter.","Report persistent reproduction as a library bug with a connection lifecycle trace."],"tags":["signalr","java","internal","invocation","state-machine","concurrency"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}