{"record":{"id":"6825cc9b8ae32dab","repo":"apache/shenyu","slug":"clock-moved-backwards-refusing-to-generate-id-for-d","errorCode":null,"errorMessage":"Clock moved backwards.  Refusing to generate id for %d milliseconds","messagePattern":"Clock moved backwards\\.  Refusing to generate id for (.+?) milliseconds","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"shenyu-common/src/main/java/org/apache/shenyu/common/utils/UUIDUtils.java","lineNumber":87,"sourceCode":"        }\n        this.workerId = workerId;\n        this.datacenterId = datacenterId;\n        this.idepoch = idepoch;\n    }\n\n    /**\n     * Gets instance.\n     *\n     * @return the instance\n     */\n    public static UUIDUtils getInstance() {\n        return ID_WORKER_UTILS;\n    }\n\n    private synchronized long nextId() {\n        long timestamp = timeGen();\n        if (timestamp < lastTimestamp) {\n            throw new RuntimeException(String.format(\"Clock moved backwards.  Refusing to generate id for %d milliseconds\", lastTimestamp - timestamp));\n        }\n        if (lastTimestamp == timestamp) {\n            sequence = (sequence + 1) & SEQUENCE_MASK;\n            if (sequence == 0) {\n                timestamp = tilNextMillis(lastTimestamp);\n            }\n        } else {\n            sequence = 0L;\n        }\n\n        lastTimestamp = timestamp;\n\n        return ((timestamp - idepoch) << TIMESTAMP_LEFT_SHIFT)\n                | (datacenterId << DATACENTER_ID_SHIFT)\n                | (workerId << WORKER_ID_SHIFT) | sequence;\n    }\n\n    private long tilNextMillis(final long lastTimestamp) {","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-common/src/main/java/org/apache/shenyu/common/utils/UUIDUtils.java#L69-L105","documentation":"UUIDUtils.nextId() is a Snowflake-style ID generator that encodes the current millisecond timestamp into each ID. If the system clock is set backwards (NTP correction, VM snapshot restore, manual change) below the last timestamp used, it throws this RuntimeException to prevent generating duplicate or non-monotonic IDs.","triggerScenarios":"Calling UUIDUtils.getInstance().getGeneratedKey() (or any ID-generation path) after the JVM clock jumps backwards relative to the last timestamp recorded in nextId().","commonSituations":"NTP daemon stepping the clock back on a host running the gateway or admin; restoring a VM/container snapshot; clock drift between host and hypervisor after live migration; manual time change during testing.","solutions":["Wait for the wall clock to catch back up past lastTimestamp (offset reported in the message), then retry ID generation","Re-sync the clock with NTP (e.g. chronyc makestep / ntpdate) ensuring it never moves backwards, or use slewing instead of stepping","Restart the application process — this resets the in-memory lastTimestamp, but only do so after fixing the clock to avoid duplicate IDs","Long-term: run instances with clock-sync guarantees (disable aggressive NTP step, avoid snapshot restores of running JVMs)"],"exampleFix":"// before\ntry {\n    long id = UUIDUtils.getInstance().getGeneratedKey();\n} catch (RuntimeException e) {\n    // process dies or request fails on clock jump\n}\n// after\nlong id;\ntry {\n    id = UUIDUtils.getInstance().getGeneratedKey();\n} catch (RuntimeException e) {\n    if (!e.getMessage().startsWith(\"Clock moved backwards\")) throw e;\n    TimeUnit.MILLISECONDS.sleep(estimateCatchUpMs(e)); // or wait via monitoring\n    id = UUIDUtils.getInstance().getGeneratedKey();\n}","handlingStrategy":"try-catch","validationCode":"// before generating: check clock is not behind a previously persisted max timestamp\nlong last = loadLastPersistedTimestamp();\nif (System.currentTimeMillis() < last) {\n    throw new IllegalStateException(\"Clock behind last issued id timestamp by \" + (last - System.currentTimeMillis()) + \" ms\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    long id = UUIDUtils.getInstance().getGeneratedKey();\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Clock moved backwards\")) {\n        // wait/retry after clock re-sync\n    } else {\n        throw e;\n    }\n}","preventionTips":["Configure NTP to slew rather than step backwards, or cap backward steps to sub-millisecond values","Never restore VM/container snapshots of a running JVM without resetting or persisting generator state","Persist the max issued timestamp and reject startup if the clock is behind it","Monitor clock skew in production (e.g. chronyc tracking / node_exporter clock metrics)"],"tags":["snowflake","clock-skew","id-generation","runtime"],"backgroundTag":"clock-moved-backwards","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}