{"record":{"id":"0ddb0a24fb3fdec0","repo":"alibaba/canal","slug":"master-slave-sourcing-type-is-unmatch-s-vs-s","errorCode":null,"errorMessage":"master/slave Sourcing type is unmatch. %s vs %s","messagePattern":"master/slave Sourcing type is unmatch\\. (.+?) vs (.+?)","errorType":"validation","errorClass":"CanalException","httpStatus":null,"severity":"error","filePath":"instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java","lineNumber":233,"sourceCode":"        // ((AbstractCanalEventSink) eventSink).setFilter(aviaterFilter);\n        // }\n        logger.info(\"init eventSink end! \\n\\t load CanalEventSink:{}\", eventSink.getClass().getName());\n    }\n\n    protected void initEventParser() {\n        logger.info(\"init eventParser begin...\");\n        SourcingType type = parameters.getSourcingType();\n\n        List<List<DataSourcing>> groupDbAddresses = parameters.getGroupDbAddresses();\n        if (!CollectionUtils.isEmpty(groupDbAddresses)) {\n            int size = groupDbAddresses.get(0).size();// 取第一个分组的数量，主备分组的数量必须一致\n            List<CanalEventParser> eventParsers = new ArrayList<>();\n            for (int i = 0; i < size; i++) {\n                List<InetSocketAddress> dbAddress = new ArrayList<>();\n                SourcingType lastType = null;\n                for (List<DataSourcing> groupDbAddress : groupDbAddresses) {\n                    if (lastType != null && !lastType.equals(groupDbAddress.get(i).getType())) {\n                        throw new CanalException(String.format(\"master/slave Sourcing type is unmatch. %s vs %s\",\n                            lastType,\n                            groupDbAddress.get(i).getType()));\n                    }\n\n                    lastType = groupDbAddress.get(i).getType();\n                    dbAddress.add(groupDbAddress.get(i).getDbAddress());\n                }\n\n                // 初始化其中的一个分组parser\n                eventParsers.add(doInitEventParser(lastType, dbAddress));\n            }\n\n            if (eventParsers.size() > 1) { // 如果存在分组，构造分组的parser\n                GroupEventParser groupEventParser = new GroupEventParser();\n                groupEventParser.setEventParsers(eventParsers);\n                this.eventParser = groupEventParser;\n            } else {\n                this.eventParser = eventParsers.get(0);","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java#L215-L251","documentation":"Thrown in initEventParser() (CanalInstanceWithManager.java:232-235) while iterating group database addresses: at each index i across the configured groups, the SourcingType must match the previous group's SourcingType at the same index. If two groups disagree (e.g. group[0][i]=MYSQL and group[1][i]=LOCALBINLOG), canal raises CanalException 'master/slave Sourcing type is unmatch. <lastType> vs <currentType>'. Canal builds one parser per index position across all groups and requires homogeneous source types per position.","triggerScenarios":"Configuring canal.instance.group.<n>.db addresses (groupDbAddresses) where the master/standby lists mix SourcingTypes at the same position — e.g. group groupA lists a MYSQL address at position 0 and group groupB lists a LOCALBINLOG or ORACLE address at position 0. The comparison runs during instance startup in initEventParser.","commonSituations":"Multi-group HA setup where one group is MySQL and another was intended as a local-binlog fallback but placed at the same index; copy-paste of group config with a different source type; mixing a TDDL/Oracle source into a MySQL group; miscounted group entries causing index misalignment.","solutions":["Align SourcingTypes per index across all groups — every group's i-th entry must share the same SourcingType (all MYSQL, or all LOCALBINLOG). The exception message names the two conflicting types to pinpoint the index.","Re-check the canal.instance.group.<groupIndex>.db.* and corresponding type settings; ensure the number of entries per group is identical (the code assumes equal size, taking groupDbAddresses.get(0).size()).","If you need heterogeneous sources, run separate canal instances rather than grouping them.","Strip stray/empty group entries that shift indices."],"exampleFix":"# before — mismatched types at index 0\ncanal.instance.group1.db.tcpHost = mysql-a:3306      # MYSQL\ncanal.instance.group2.localBinlog.dir = /data/binlog  # LOCALBINLOG at same index\n\n# after — homogeneous per index\ncanal.instance.group1.db.tcpHost = mysql-a:3306\ncanal.instance.group2.db.tcpHost = mysql-b:3306","handlingStrategy":"validation","validationCode":"// Validate that every group has the same SourcingType at each index before starting\nList<List<DataSourcing>> groups = parameters.getGroupDbAddresses();\nif (!CollectionUtils.isEmpty(groups)) {\n    int size = groups.get(0).size();\n    for (int i = 0; i < size; i++) {\n        SourcingType first = groups.get(0).get(i).getType();\n        for (int g = 1; g < groups.size(); g++) {\n            if (!first.equals(groups.get(g).get(i).getType())) {\n                throw new IllegalArgumentException(String.format(\n                    \"SourcingType mismatch at index %d: %s vs %s\", i, first, groups.get(g).get(i).getType()));\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep SourcingTypes homogeneous per index across all configured groups.","Ensure equal number of entries per group (the code assumes uniform size).","Run heterogeneous sources as separate canal instances.","Double-check group index alignment after editing canal.instance.group.* properties."],"tags":["configuration","ha","group","sourcing-type","event-parser","instance-manager"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}