alibaba/canal · error · UnsupportedOperationException

unknown mode :

Error message

unknown mode :

What it means

Thrown inside the instanceGenerator lambda when config.getMode() is neither MANAGER nor SPRING. Identical structure to error 293 but at instance-creation time rather than monitor-creation time. Because InstanceMode only has SPRING and MANAGER, this branch is defensive dead code unless the enum is extended.

Source

Thrown at deployer/src/main/java/com/alibaba/otter/canal/deployer/CanalController.java:394

        }

        instanceGenerator = destination -> {
            InstanceConfig config = instanceConfigs.get(destination);
            if (config == null) {
                throw new CanalServerException("can't find destination:" + destination);
            }

            if (config.getMode().isManager()) {
                PlainCanalInstanceGenerator instanceGenerator = new PlainCanalInstanceGenerator(properties);
                instanceGenerator.setCanalConfigClient(managerClients.get(config.getManagerAddress()));
                instanceGenerator.setSpringXml(config.getSpringXml());
                return instanceGenerator.generate(destination);
            } else if (config.getMode().isSpring()) {
                SpringCanalInstanceGenerator instanceGenerator = new SpringCanalInstanceGenerator();
                instanceGenerator.setSpringXml(config.getSpringXml());
                return instanceGenerator.generate(destination);
            } else {
                throw new UnsupportedOperationException("unknown mode :" + config.getMode());
            }

        };

        return globalConfig;
    }

    private PlainCanalConfigClient getManagerClient(String managerAddress) {
        return new PlainCanalConfigClient(managerAddress, this.adminUser, this.adminPasswd, this.registerIp, adminPort);
    }

    private void initInstanceConfig(Properties properties) {
        String destinationStr = getDestinations(properties);
        String[] destinations = StringUtils.split(destinationStr, CanalConstants.CANAL_DESTINATION_SPLIT);

        for (String destination : destinations) {
            InstanceConfig config = parseInstanceConfig(properties, destination);
            InstanceConfig oldConfig = instanceConfigs.put(destination, config);

View on GitHub (pinned to 87be50e876)

Solutions

  1. Ensure canal.instance.global.mode (and per-instance mode) is spring or manager.
  2. If mode is null, set it explicitly — a null mode falls through both branches to this throw.
  3. On a custom fork, add the new mode's instance-generation logic before the else.
Defensive patterns

Strategy: validation

Validate before calling

InstanceMode mode = config.getMode();
if (mode == null || (!mode.isManager() && !mode.isSpring())) {
    throw new IllegalArgumentException("Instance mode must be spring or manager, got: " + mode);
}

Prevention

When it happens

Trigger: An InstanceConfig resolves to a mode that is not spring or manager. In practice unreachable because the enum has no other values; a bad mode string fails earlier at valueOf.

Common situations: Custom Canal fork that added an InstanceMode without handling it here; a deserialized InstanceConfig carrying a null mode (getMode returns null, both isManager/isSpring false).

Related errors


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