alibaba/canal · error · ZkException

Unable to connect to {}

Error message

Unable to connect to {}

What it means

Thrown by ZooKeeperx.connect when the java.io.IOException escapes from 'new ZooKeeper(zkServers, timeout, watcher)'. It is wrapped as ZkException (an I0Itec zkclient runtime exception) carrying the connect string. The root cause is almost always network/connect-string: unreachable hosts, DNS failure, malformed connect string, or firewall dropping the 2181 port.

Source

Thrown at common/src/main/java/com/alibaba/otter/canal/common/zookeeper/ZooKeeperx.java:76

        ReflectionUtils.makeAccessible(zookeeperLockField);
        ReflectionUtils.makeAccessible(zookeeperFiled);
        Lock _zookeeperLock = (ReentrantLock) ReflectionUtils.getField(zookeeperLockField, this);
        ZooKeeper _zk = (ZooKeeper) ReflectionUtils.getField(zookeeperFiled, this);

        _zookeeperLock.lock();
        try {
            if (_zk != null) {
                throw new IllegalStateException("zk client has already been started");
            }
            String zkServers = _serversList.get(0);

            try {
                logger.debug("Creating new ZookKeeper instance to connect to " + zkServers + ".");
                _zk = new ZooKeeper(zkServers, _sessionTimeOut, watcher);
                configMutliCluster(_zk);
                ReflectionUtils.setField(zookeeperFiled, this, _zk);
            } catch (IOException e) {
                throw new ZkException("Unable to connect to " + zkServers, e);
            }
        } finally {
            _zookeeperLock.unlock();
        }
    }

    // ===============================

    public void configMutliCluster(ZooKeeper zk) {
        if (_serversList.size() == 1) {
            return;
        }
        String cluster1 = _serversList.get(0);
        try {
            if (_serversList.size() > 1) {
                // 强制的声明accessible
                ReflectionUtils.makeAccessible(clientCnxnField);
                ReflectionUtils.makeAccessible(hostProviderField);

View on GitHub (pinned to 87be50e876)

Solutions

  1. Verify the ZK ensemble is reachable: run 'echo ruok | nc <host> 2181' or 'zkCli.sh -server <servers>' from the canal host.
  2. Correct canal.zkServers in canal.properties to point at a live ensemble (host:port, comma-separated, ';' separates multi-cluster groups).
  3. Open firewall/security-group egress on port 2181 from the canal node to the ZK hosts.
  4. If transient, retry startup after confirming network, or enable canal-level reconnect rather than a manual double-connect.

Example fix

// before
canal.zkServers = 127.0.0.2:2181   // unreachable
// after
canal.zkServers = zk1.prod:2181,zk2.prod:2181,zk3.prod:2181
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight check that the ZK ensemble is reachable before constructing ZooKeeperx
boolean reachable(String host, int port, int timeoutMs) {
    try (java.net.Socket s = new java.net.Socket()) {
        s.connect(new java.net.InetSocketAddress(host, port), timeoutMs);
        return true;
    } catch (IOException e) {
        return false;
    }
}
// if (!reachable("zk1", 2181, 2000)) { delay/abort startup }

Try / catch

int attempt = 0;
while (true) {
    try {
        zkClient.connect(watcher);
        break;
    } catch (org.I0Itec.zkclient.exception.ZkException e) {
        if (e.getMessage().startsWith("Unable to connect") && ++attempt < MAX_RETRIES) {
            // backoff and retry
        } else throw e;
    }
}

Prevention

When it happens

Trigger: new ZooKeeper(zkServers,...) throws IOException because no ZK ensemble member at the first cluster entry is reachable; connect string is empty/blank/unresolvable; session-timeout vs. network-partition mismatch.

Common situations: Wrong canal.zkServers value (typo, stale host); ZK ensemble down during canal startup; security group/firewall blocks port 2181; Kerberos/SASL misconfiguration causing handshake IOException; running canal in a container whose DNS cannot resolve ZK hostnames.

Related errors


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