{"record":{"id":"f8449e26d7dc58ff","repo":"alibaba/canal","slug":"unsupport-hamode-for","errorCode":null,"errorMessage":"unsupport HAMode for {}","messagePattern":"unsupport HAMode for (.+?)","errorType":"validation","errorClass":"CanalException","httpStatus":null,"severity":"error","filePath":"instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java","lineNumber":433,"sourceCode":"            MysqlEventParser mysqlEventParser = (MysqlEventParser) eventParser;\n\n            // 初始化haController，绑定与eventParser的关系，haController会控制eventParser\n            CanalHAController haController = initHaController();\n            mysqlEventParser.setHaController(haController);\n        }\n        return eventParser;\n    }\n\n    protected CanalHAController initHaController() {\n        logger.info(\"init haController begin...\");\n        HAMode haMode = parameters.getHaMode();\n        CanalHAController haController = null;\n        if (haMode.isHeartBeat()) {\n            haController = new HeartBeatHAController();\n            ((HeartBeatHAController) haController).setDetectingRetryTimes(parameters.getDetectingRetryTimes());\n            ((HeartBeatHAController) haController).setSwitchEnable(parameters.getHeartbeatHaEnable());\n        } else {\n            throw new CanalException(\"unsupport HAMode for \" + haMode);\n        }\n        logger.info(\"init haController end! \\n\\t load CanalHAController:{}\", haController.getClass().getName());\n\n        return haController;\n    }\n\n    protected CanalLogPositionManager initLogPositionManager() {\n        logger.info(\"init logPositionPersistManager begin...\");\n        IndexMode indexMode = parameters.getIndexMode();\n        CanalLogPositionManager logPositionManager;\n        if (indexMode.isMemory()) {\n            logPositionManager = new MemoryLogPositionManager();\n        } else if (indexMode.isZookeeper()) {\n            logPositionManager = new ZooKeeperLogPositionManager(getZkclientx());\n        } else if (indexMode.isMixed()) {\n            MemoryLogPositionManager memoryLogPositionManager = new MemoryLogPositionManager();\n            ZooKeeperLogPositionManager zooKeeperLogPositionManager = new ZooKeeperLogPositionManager(getZkclientx());\n            logPositionManager = new PeriodMixedLogPositionManager(memoryLogPositionManager,","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java#L415-L451","documentation":"Thrown in initHaController() (CanalInstanceWithManager.java:432-433) when HAMode is not HEARTBEAT. Of the two HAMode constants (HEARTBEAT, MEDIA), only HEARTBEAT is implemented (HeartBeatHAController). MEDIA ('otter media') has no controller, so selecting it — or any future constant — falls into the else and raises CanalException 'unsupport HAMode for ' + haMode.","triggerScenarios":"Configuring canal.instance.haMode = MEDIA (or a custom HAMode whose isHeartBeat() returns false) and starting a MysqlEventParser instance, which calls initHaController during doInitEventParser. Only HEARTBEAT is wired.","commonSituations":"Operator selects MEDIA expecting otter-integration HA without realising canal standalone does not implement it; legacy config ported from an otter-managed deployment; misunderstanding the HAMode options (HAMode here is about MySQL master/standby switching, not canal-server clustering, which is handled separately via zookeeper).","solutions":["Set canal.instance.haMode = HEARTBEAT (the implemented controller). It uses heartbeat detection to switch between master and standby MySQL.","For canal-server-level HA (multiple canal instances coordinating leadership), use canal.zkClusters + the canal server deployer HA mechanism — that is separate from canal.instance.haMode.","If MEDIA is genuinely needed, integrate with otter rather than standalone canal."],"exampleFix":"# before\ncanal.instance.haMode = MEDIA\n\n# after\ncanal.instance.haMode = HEARTBEAT\ncanal.instance.heartbeatHaEnable = true","handlingStrategy":"validation","validationCode":"if (!parameters.getHaMode().isHeartBeat()) {\n    throw new IllegalArgumentException(\n        \"Unsupported canal.instance.haMode: \" + parameters.getHaMode()\n        + \" (only HEARTBEAT is implemented for MySQL master/standby switching)\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use canal.instance.haMode = HEARTBEAT.","For canal-server-level HA use canal.zkClusters + the deployer HA mechanism, not canal.instance.haMode.","Do not select MEDIA for standalone canal."],"tags":["configuration","ha","ha-controller","instance-manager","unsupported"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}