MyCATApache/Mycat-Server · error · IllegalStateException

IncrSequenceZKHandler should be loaded first!

Error message

IncrSequenceZKHandler should be loaded first!

What it means

fetchNextPeriod() requires per-thread state (the InterProcessSemaphoreMutex) that is only populated by handle() during load()/initializeZK(). If the mutex ThreadLocal is null when fetchNextPeriod runs, the ZK handler was never initialized on this thread, so it throws IllegalStateException. Without the lock it is unsafe to fetch a new ID period from ZooKeeper.

Solutions

  1. Ensure IncrSequenceZKHandler.load() is invoked (and succeeds) before any nextId()/fetchNextPeriod call
  2. Verify ZK connectivity and ZkConfig cluster ID so initializeZK() completes instead of failing silently inside load()'s catch block
  3. Call threadLocalLoad() on the current thread before using the handler if worker threads are involved

Example fix

// before
IncrSequenceZKHandler.getInstance().nextId("ORDERS"); // handler never loaded
// after
IncrSequenceZKHandler handler = IncrSequenceZKHandler.getInstance();
handler.load();
long id = handler.nextId("ORDERS");
Defensive patterns

Strategy: validation

Validate before calling

if (!zkHandlerInitialized) {
    handler.load(); // must succeed before any nextId() call
}
// confirm load() did not fail: initializeZK errors are only logged, not rethrown

Try / catch

try {
    long id = handler.nextId(prefixName);
} catch (IllegalStateException e) {
    LOGGER.error("ZK sequence handler not initialized on this thread", e);
    handler.threadLocalLoad();
    long id = handler.nextId(prefixName);
}

Prevention

When it happens

Trigger: Calling fetchNextPeriod (directly or via handle/getParaValMap -> threadLocalLoad) on a thread where IncrSequenceZKHandler.load() or initializeZK() was never run — e.g. ZkConfig/ZK URL missing so load() failed, or load() was skipped entirely.

Common situations: ZooKeeper unavailable at startup: load() catches the exception and only logs it, so the handler instance exists but was never initialized; calling nextId() before load(); using the handler from a worker thread that never ran threadLocalLoad().

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11). Data as JSON: /api/errors/6ab5931cddf0acdd. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/mycat/route/sequence/handler/IncrSequenceZKHandler.java:173

        Map<String, Map<String, String>> tableParaValMap = tableParaValMapThreadLocal.get();
        if (tableParaValMap == null) {
            try {
                threadLocalLoad();
            } catch (Exception e) {
                LOGGER.error("Error caught while loding configuration within current thread:" + e.getCause());
            }
            tableParaValMap = tableParaValMapThreadLocal.get();
        }
        Map<String, String> paraValMap = tableParaValMap.get(prefixName);
        return paraValMap;
    }

    @Override
    public Boolean fetchNextPeriod(String prefixName) {
        InterProcessSemaphoreMutex interProcessSemaphoreMutex = interProcessSemaphoreMutexThreadLocal.get();
        try {
            if (interProcessSemaphoreMutex == null) {
                throw new IllegalStateException("IncrSequenceZKHandler should be loaded first!");
            }
            interProcessSemaphoreMutex.acquire();
            Map<String, Map<String, String>> tableParaValMap = tableParaValMapThreadLocal.get();
            if (tableParaValMap == null) {
                throw new IllegalStateException("IncrSequenceZKHandler should be loaded first!");
            }
            Map<String, String> paraValMap = tableParaValMap.get(prefixName);
            if (paraValMap == null) {
                throw new IllegalStateException("IncrSequenceZKHandler should be loaded first!");
            }
            if (paraValMap.get(prefixName + KEY_MAX_NAME) == null) {
                paraValMap.put(prefixName + KEY_MAX_NAME, props.getProperty(prefixName + KEY_MAX_NAME));
            }
            if (paraValMap.get(prefixName + KEY_MIN_NAME) == null) {
                paraValMap.put(prefixName + KEY_MIN_NAME, props.getProperty(prefixName + KEY_MIN_NAME));
            }
            if (paraValMap.get(prefixName + KEY_CUR_NAME) == null) {
                paraValMap.put(prefixName + KEY_CUR_NAME, props.getProperty(prefixName + KEY_CUR_NAME));

View on GitHub (pinned to 65f8d8beb7)