{"record":{"id":"d14fdeb920a331b3","repo":"redisson/redisson","slug":"connection-already-subscribed-d14fde","errorCode":null,"errorMessage":"Connection already subscribed","messagePattern":"Connection already subscribed","errorType":"exception","errorClass":"RedisSubscribedConnectionException","httpStatus":null,"severity":"error","filePath":"redisson-spring/redisson-spring-data/redisson-spring-data-22/src/main/java/org/redisson/spring/data/connection/RedissonConnection.java","lineNumber":1635,"sourceCode":"        return subscription;\n    }\n\n    @Override\n    public Long publish(byte[] channel, byte[] message) {\n        return write(channel, StringCodec.INSTANCE, RedisCommands.PUBLISH, channel, message);\n    }\n\n    @Override\n    public void subscribe(MessageListener listener, byte[]... channels) {\n        checkSubscription();\n        \n        subscription = new RedissonSubscription(executorService, listener);\n        subscription.subscribe(channels);\n    }\n\n    private void checkSubscription() {\n        if (subscription != null) {\n            throw new RedisSubscribedConnectionException(\"Connection already subscribed\");\n        }\n        \n        if (isQueueing()) {\n            throw new UnsupportedOperationException(\"Not supported in queueing mode\");\n        }\n        if (isPipelined()) {\n            throw new UnsupportedOperationException(\"Not supported in pipelined mode\");\n        }\n    }\n\n    @Override\n    public void pSubscribe(MessageListener listener, byte[]... patterns) {\n        checkSubscription();\n        \n        subscription = new RedissonSubscription(executorService, listener);\n        subscription.pSubscribe(patterns);\n    }\n","sourceCodeStart":1617,"sourceCodeEnd":1653,"githubUrl":"https://github.com/redisson/redisson/blob/91188987c2a9023e7fedabff758681ad9b107f25/redisson-spring/redisson-spring-data/redisson-spring-data-22/src/main/java/org/redisson/spring/data/connection/RedissonConnection.java#L1617-L1653","documentation":"Redisson's RedissonConnection keeps at most one active RedisSubscription per connection. subscribe(MessageListener, byte[]...) calls checkSubscription(), which throws RedisSubscribedConnectionException when the subscription field is already non-null. This mirrors Redis semantics where a connection entering subscribe mode is dedicated to pub/sub and cannot start a second subscription.","triggerScenarios":"Calling subscribe() (or pSubscribe(), which shares checkSubscription()) twice on the same RedissonConnection without closing/unsubscribing the first subscription; e.g. two listeners registered through the same RedisTemplate bound to one connection.","commonSituations":"Registering multiple MessageListener beans through a single RedisConnection; re-subscribing after a reconnect handler runs on the same connection; integration tests that reuse a connection across test cases without unsubscribing.","solutions":["Use a fresh connection (RedisConnectionFactory.getConnection()) for each independent subscription instead of reusing the subscribed one.","Unsubscribe and release the existing subscription before subscribing again on the same connection.","Let Spring Data Redis' RedisMessageListenerContainer manage subscriptions — it dispatches each listener over dedicated connections.","Wrap subscribe() in try-catch for RedisSubscribedConnectionException if accidental reuse is possible."],"exampleFix":"// before\nRedisConnection conn = factory.getConnection();\nconn.subscribe(listenerA, \"ch1\".getBytes());\nconn.subscribe(listenerB, \"ch2\".getBytes()); // throws\n\n// after\nRedisConnection connA = factory.getConnection();\nconnA.subscribe(listenerA, \"ch1\".getBytes());\nRedisConnection connB = factory.getConnection();\nconnB.subscribe(listenerB, \"ch2\".getBytes());","handlingStrategy":"validation","validationCode":"// Spring Data Redis does not expose isSubscribed(); track subscriptions yourself or\n// rely on RedisMessageListenerContainer. If managing manually, keep one connection per subscription:\nMap<MessageListener, RedisConnection> active = new ConcurrentHashMap<>();\nRedisConnection conn = active.computeIfAbsent(listener, k -> factory.getConnection());","typeGuard":null,"tryCatchPattern":"try {\n    conn.subscribe(listener, channel);\n} catch (RedisSubscribedConnectionException e) {\n    // connection already dedicated to pub/sub: open a new one\n    RedisConnection fresh = factory.getConnection();\n    fresh.subscribe(listener, channel);\n}","preventionTips":["One subscription per connection — never reuse a subscribed RedissonConnection.","Prefer RedisMessageListenerContainer for all listener registration.","In reconnect handlers, create a new connection instead of resubscribing on the old one."],"tags":["redis","pubsub","spring-data-redis","connection-management"],"backgroundTag":null,"analyzedSha":"91188987c2a9023e7fedabff758681ad9b107f25","analyzedAt":"2026-08-14T11:39:42.619Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}