{"record":{"id":"6f0a38b326c43a8c","repo":"quarkusio/quarkus","slug":"channel-cannot-be-blank","errorCode":null,"errorMessage":"Channel cannot be blank","messagePattern":"Channel cannot be blank","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactivePubSubCommandsImpl.java","lineNumber":166,"sourceCode":"\n        return RedisConnections.withNewLongLivedConnection(client, conn -> {\n            RedisAPI api = RedisAPI.api(conn);\n            ReactiveRedisPatternSubscriberImpl subscriber = new ReactiveRedisPatternSubscriberImpl(conn, api, patterns,\n                    onMessage, onEnd, onException);\n            return subscriber.subscribe()\n                    .replaceWith(subscriber);\n        });\n    }\n\n    private void validateChannels(List<String> channels) {\n        notNullOrEmpty(channels, \"channels\");\n\n        for (String pattern : channels) {\n            if (pattern == null) {\n                throw new IllegalArgumentException(\"Channel must not be null\");\n            }\n            if (pattern.isBlank()) {\n                throw new IllegalArgumentException(\"Channel cannot be blank\");\n            }\n        }\n    }\n\n    @Override\n    public Uni<ReactiveRedisSubscriber> subscribe(List<String> channels, Consumer<V> onMessage, Runnable onEnd,\n            Consumer<Throwable> onException) {\n        nonNull(onMessage, \"onMessage\");\n        validateChannels(channels);\n\n        return RedisConnections.withNewLongLivedConnection(client, conn -> {\n            RedisAPI api = RedisAPI.api(conn);\n            ReactiveAbstractRedisSubscriberImpl subscriber = new ReactiveAbstractRedisSubscriberImpl(conn, api,\n                    channels, (channel, value) -> onMessage.accept(value), onEnd, onException);\n            return subscriber.subscribe()\n                    .replaceWith(subscriber);\n        });\n    }","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/runtime/datasource/ReactivePubSubCommandsImpl.java#L148-L184","documentation":"Quarkus Redis pub/sub validation: subscribe() rejects channel names that are null or blank because Redis PUB/SUB requires non-empty channel strings. A blank channel would produce a malformed SUBSCRIBE command that Lettuce/Redis cannot resolve.","triggerScenarios":"Calling ReactivePubSubCommandsImpl.subscribe(List.of(\"\"), ...) or subscribe(List.of(\"  \"), ...) or passing a list containing a blank entry; also psubscribe with blank patterns via the same validateChannels path.","commonSituations":"Channel names built from configuration properties or environment variables that are empty/whitespace; dynamically computed topic names where string interpolation yields an empty string; deserialized payloads missing the channel field.","solutions":["Set a non-blank channel name before calling subscribe","Trim/normalize configured channel names and fail fast at startup if blank","Filter or validate the list before subscribing"],"exampleFix":"// before\nString channel = config.get(\"topic\");\nredis.subscribe(List.of(channel), msg -> {}, () -> {});\n// after\nString channel = config.get(\"topic\");\nObjects.requireNonNull(channel, \"channel\");\nif (channel.isBlank()) throw new IllegalStateException(\"topic config must not be blank\");\nredis.subscribe(List.of(channel), msg -> {}, () -> {});","handlingStrategy":"validation","validationCode":"List<String> safeChannels = channels == null ? List.of() : channels;\nif (safeChannels.isEmpty() || safeChannels.stream().anyMatch(c -> c == null || c.isBlank())) {\n    throw new IllegalArgumentException(\"all channels must be non-blank strings\");\n}","typeGuard":"static boolean isValidChannels(List<String> channels) {\n    return channels != null && !channels.isEmpty()\n        && channels.stream().allMatch(c -> c != null && !c.isBlank());\n}","tryCatchPattern":"try {\n    redis.subscribe(channels, onMessage, onEnd);\n} catch (IllegalArgumentException e) {\n    log.error(\"Invalid pub/sub channel: \" + e.getMessage());\n}","preventionTips":["Trim channel names read from config/environment","Fail at application startup if a configured topic is blank","Centralize topic-name constants instead of inline strings","Write a unit test covering blank-channel rejection"],"tags":["validation","redis","pubsub","illegal-argument"],"backgroundTag":"blank-required-string","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}