alibaba/canal · error · CanalException

unsupport HAMode for {}

Error message

unsupport HAMode for {}

What it means

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.

Source

Thrown at instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java:433

            MysqlEventParser mysqlEventParser = (MysqlEventParser) eventParser;

            // 初始化haController,绑定与eventParser的关系,haController会控制eventParser
            CanalHAController haController = initHaController();
            mysqlEventParser.setHaController(haController);
        }
        return eventParser;
    }

    protected CanalHAController initHaController() {
        logger.info("init haController begin...");
        HAMode haMode = parameters.getHaMode();
        CanalHAController haController = null;
        if (haMode.isHeartBeat()) {
            haController = new HeartBeatHAController();
            ((HeartBeatHAController) haController).setDetectingRetryTimes(parameters.getDetectingRetryTimes());
            ((HeartBeatHAController) haController).setSwitchEnable(parameters.getHeartbeatHaEnable());
        } else {
            throw new CanalException("unsupport HAMode for " + haMode);
        }
        logger.info("init haController end! \n\t load CanalHAController:{}", haController.getClass().getName());

        return haController;
    }

    protected CanalLogPositionManager initLogPositionManager() {
        logger.info("init logPositionPersistManager begin...");
        IndexMode indexMode = parameters.getIndexMode();
        CanalLogPositionManager logPositionManager;
        if (indexMode.isMemory()) {
            logPositionManager = new MemoryLogPositionManager();
        } else if (indexMode.isZookeeper()) {
            logPositionManager = new ZooKeeperLogPositionManager(getZkclientx());
        } else if (indexMode.isMixed()) {
            MemoryLogPositionManager memoryLogPositionManager = new MemoryLogPositionManager();
            ZooKeeperLogPositionManager zooKeeperLogPositionManager = new ZooKeeperLogPositionManager(getZkclientx());
            logPositionManager = new PeriodMixedLogPositionManager(memoryLogPositionManager,

View on GitHub (pinned to 87be50e876)

Solutions

  1. Set canal.instance.haMode = HEARTBEAT (the implemented controller). It uses heartbeat detection to switch between master and standby MySQL.
  2. 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.
  3. If MEDIA is genuinely needed, integrate with otter rather than standalone canal.

Example fix

# before
canal.instance.haMode = MEDIA

# after
canal.instance.haMode = HEARTBEAT
canal.instance.heartbeatHaEnable = true
Defensive patterns

Strategy: validation

Validate before calling

if (!parameters.getHaMode().isHeartBeat()) {
    throw new IllegalArgumentException(
        "Unsupported canal.instance.haMode: " + parameters.getHaMode()
        + " (only HEARTBEAT is implemented for MySQL master/standby switching)");
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/f8449e26d7dc58ff. Report an issue: GitHub.