alibaba/canal · error · CanalServerException

ClientIdentity:%s should subscribe first

Error message

ClientIdentity:%s should subscribe first

What it means

Thrown by the private checkSubscribe() guard, which is invoked at the top of get()/ack()/rollback() before any batch operation. It asks MetaManager.hasSubscribe(clientIdentity); if false it aborts because batch tracking and cursor positioning require an active subscription for that destination+clientId.

Source

Thrown at server/src/main/java/com/alibaba/otter/canal/server/embedded/CanalServerWithEmbedded.java:527

            return eventStore.tryGet(start, batchSize);
        } else {
            try {
                if (timeout <= 0) {
                    return eventStore.get(start, batchSize);
                } else {
                    return eventStore.get(start, batchSize, timeout, unit);
                }
            } catch (Exception e) {
                throw new CanalServerException(e);
            }
        }
    }

    private void checkSubscribe(ClientIdentity clientIdentity) {
        CanalInstance canalInstance = canalInstances.get(clientIdentity.getDestination());
        boolean hasSubscribe = canalInstance.getMetaManager().hasSubscribe(clientIdentity);
        if (!hasSubscribe) {
            throw new CanalServerException(String.format("ClientIdentity:%s should subscribe first",
                clientIdentity.toString()));
        }
    }

    private void checkStart(String destination) {
        if (!isStart(destination)) {
            throw new CanalServerException(String.format("destination:%s should start first", destination));
        }
    }

    private void loadCanalMetrics() {
        ServiceLoader<CanalMetricsProvider> providers = ServiceLoader.load(CanalMetricsProvider.class);
        List<CanalMetricsProvider> list = new ArrayList<>();
        for (CanalMetricsProvider provider : providers) {
            list.add(provider);
        }

        if (list.isEmpty()) {

View on GitHub (pinned to 87be50e876)

Solutions

  1. Call server.subscribe(clientIdentity) and wait for it to succeed before any get/ack/rollback.
  2. Verify the destination string in the ClientIdentity matches exactly between subscribe and subsequent calls.
  3. If using a memory MetaManager, re-subscribe after every server restart; use ZooKeeper MetaManager for persistence.
  4. Add a subscription readiness check in client startup before entering the consume loop.

Example fix

// before: get without subscribe
ClientIdentity cid = new ClientIdentity(destination, clientId);
Message msg = server.get(cid, 1000, 1L, TimeUnit.SECONDS);
// after: subscribe first
ClientIdentity cid = new ClientIdentity(destination, (short) 1001);
server.subscribe(cid); // register subscription
Message msg = server.get(cid, 1000, 1L, TimeUnit.SECONDS);
Defensive patterns

Strategy: validation

Validate before calling

// verify subscription exists before any batch operation
if (!metaManager.hasSubscribe(clientIdentity)) {
    server.subscribe(clientIdentity);
}

Try / catch

try {
    server.get(clientId, batchSize, timeout, unit);
} catch (CanalServerException e) {
    if (e.getMessage().contains("should subscribe first")) {
        server.subscribe(clientId);
        return server.get(clientId, batchSize, timeout, unit);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling get(), ack(), or rollback() on a ClientIdentity whose subscribe(destination, filter) was never called, was called for a different destination, or whose subscription was cleared. Also fires if the MetaManager lost the subscription record (e.g. in-memory MetaManager after a server restart).

Common situations: Client connects and immediately calls get() without subscribe(); client subscribes to destination A then queries destination B; server restart with a memory-backed MetaManager (no ZooKeeper) wipes subscriptions; typo in destination name between subscribe and get.

Related errors


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