{"record":{"id":"ff776e9d319e9ee9","repo":"alibaba/canal","slug":"pattern-topic-cannot-multi","errorCode":null,"errorMessage":"pattern topic cannot multi: {}","messagePattern":"pattern topic cannot multi: (.+?)","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"common/src/main/java/com/alibaba/otter/canal/common/utils/MQUtil.java","lineNumber":68,"sourceCode":"    public static void checkTopicWithErr(String... topics) {\n        if (null == topics || 0 == topics.length) {\n            throw new NullPointerException(\"topic cannot null\");\n        }\n\n        if (1 == topics.length) {\n            boolean ok = checkTopic(topics[0]);\n            if (ok) {\n                return;\n            }\n            throw new RuntimeException(\"topic invalid: \" + topics[0]);\n        }\n\n        for (String t : topics) {\n            if (!checkTopic(t)) {\n                throw new IllegalArgumentException(\"topic invalid: \" + t);\n            }\n            if (isPatternTopic(t)) {\n                throw new RuntimeException(\"pattern topic cannot multi: \" + t);\n            }\n        }\n    }\n\n    /**\n     * 检查tag有效性\n     *\n     * @param tags\n     */\n    public static void checkTagWithErr(String... tags) {\n        // 空表示不使用tag\n        if (null == tags || 0 == tags.length) {\n            return;\n        }\n\n//        if (1 == tags.length && (null == tags[0] || 0 == tags[0].trim().length())) {\n//            throw new NullPointerException(\"tag cannot null\");\n//        }","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/common/src/main/java/com/alibaba/otter/canal/common/utils/MQUtil.java#L50-L86","documentation":"Thrown by MQUtil.checkTopicWithErr() in the multi-topic loop when a topic is detected as a pattern topic (via isPatternTopic()) while multiple topics are specified. isPatternTopic() returns true if the topic contains any character outside `^[0-9a-z:/-]+$` — notably, topics containing `*` (wildcard) are considered pattern topics. Canal does not allow combining pattern subscription with multiple explicit topics because the semantics would be ambiguous.","triggerScenarios":"Calling checkTopicWithErr() with more than one topic where at least one contains wildcard/pattern characters (asterisk, dot, or other non-literal chars) — e.g. passing both 'orders' and 'order-*'.","commonSituations":"Configuring canal MQ to subscribe to multiple topics where one uses a wildcard pattern; mixing explicit topic names with pattern subscriptions in the same producer; misunderstanding that `*` in a topic name triggers pattern mode.","solutions":["Use either a single pattern topic OR multiple explicit topics — never both together.","If a wildcard is needed, use only one topic entry containing the pattern.","Replace wildcard topics with explicit topic names if multiple topics are required."],"exampleFix":"// before — mixing pattern and explicit topics\ncanal.mq.topic=orders,order-*,payments\n\n// after — choose one approach\n// option A: single pattern topic\ncanal.mq.topic=order-*\n// option B: all explicit topics\ncanal.mq.topic=orders,order-created,order-updated,payments","handlingStrategy":"validation","validationCode":"// Detect pattern topics before calling checkTopicWithErr\nif (topics.length > 1) {\n    for (String t : topics) {\n        // isPatternTopic: contains chars outside [0-9a-z:/-]\n        if (!t.matches(\"^[0-9a-z:/-]+$\")) {\n            throw new IllegalArgumentException(\n                \"Pattern topic '\" + t + \"' cannot be combined with multiple topics\");\n        }\n    }\n}\nMQUtil.checkTopicWithErr(topics);","typeGuard":"public static boolean isPatternTopic(String topic) {\n    return topic != null && !topic.matches(\"^[0-9a-z:/-]+$\");\n}\n\npublic static boolean isSafeMultiTopic(String... topics) {\n    if (topics == null || topics.length <= 1) return true;\n    for (String t : topics) {\n        if (isPatternTopic(t)) return false;\n    }\n    return true;\n}","tryCatchPattern":"try {\n    MQUtil.checkTopicWithErr(topics);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"pattern topic cannot multi:\")) {\n        logger.error(\"Cannot mix pattern topics with multiple topics. Use one or the other.\");\n    }\n    throw e;\n}","preventionTips":["Use a single pattern topic OR multiple explicit topics — never both.","If a wildcard is needed, configure only one topic entry with the pattern.","Review canal MQ topic configuration to ensure no asterisks appear alongside multiple topics."],"tags":["mq","topic-validation","pattern-subscription","config-error"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}