alibaba/canal · error · CanalServerException

invalid destinations expr

Error message

invalid destinations expr 

What it means

Thrown by CanalController.parseExpr when a destinations expression (canal.instance.destinations.expr) does not match the expected 'prefix{start-end}' pattern. The method splits on '{' and '}', then applies regex (\d+)-(\d+) to the inner range. If the braces are missing, the range isn't two hyphen-separated integers, or the format is otherwise malformed, it throws CanalServerException.

Source

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

        range = StringUtils.substringBefore(range, "}");

        String regex = "(\\d+)-(\\d+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(range);
        if (matcher.find()) {
            String head = matcher.group(1);
            String tail = matcher.group(2);
            int start = Integer.parseInt(head);
            int end = Integer.parseInt(tail);

            List<String> list = new ArrayList<>();
            for (int i = start; i <= end; i++) {
                String d = prefix + i;
                list.add(d);
            }
            return list.stream().map(Object::toString).collect(Collectors.joining(","));
        } else {
            throw new CanalServerException("invalid destinations expr " + expr);
        }
    }

    public void start() throws Throwable {
        logger.info("## start the canal server[{}({}):{}]", ip, registerIp, port);
        // 创建整个canal的工作节点
        final String path = ZookeeperPathUtils.getCanalClusterNode(registerIp + ":" + port);
        initCid(path);
        if (zkclientx != null) {
            this.zkclientx.subscribeStateChanges(new IZkStateListener() {

                public void handleStateChanged(KeeperState state) throws Exception {

                }

                public void handleNewSession() throws Exception {
                    initCid(path);
                }

View on GitHub (pinned to 87be50e876)

Solutions

  1. Use the exact format prefix{start-end}, e.g. canal.instance.destinations.expr = topic{1-100}.
  2. For a plain comma-separated list, use canal.destinations instead of the expr property.
  3. Ensure start and end are integers and start <= end.
  4. Do not nest additional characters inside the braces.

Example fix

# before
canal.instance.destinations.expr = topic1,topic2
# after (for a list, use the plain property)
canal.destinations = topic1,topic2
# or (for a range)
canal.instance.destinations.expr = topic{1-2}
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern RANGE = Pattern.compile("^(.*)\\{(\\d+)-(\\d+)\\}$");
boolean isValidDestinationsExpr(String expr) {
    return expr != null && RANGE.matcher(expr).matches();
}

Prevention

When it happens

Trigger: Setting canal.instance.destinations.expr to a value without the {N-M} range syntax, e.g. 'topic1,topic2' (use canal.destinations for a plain list), or 'topic{1-100' (missing closing brace), or 'topic{a-b}' (non-numeric).

Common situations: Confusing the expression syntax (range expansion) with the plain comma-separated canal.destinations list; missing or misplaced braces; using characters instead of integers in the range.

Related errors


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