apache/shenyu · critical · RuntimeException
Clock moved backwards. Refusing to generate id for
Error message
Clock moved backwards. Refusing to generate id for %d milliseconds
What it means
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.
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)
Example fix
// before
try {
long id = UUIDUtils.getInstance().getGeneratedKey();
} catch (RuntimeException e) {
// process dies or request fails on clock jump
}
// after
long id;
try {
id = UUIDUtils.getInstance().getGeneratedKey();
} catch (RuntimeException e) {
if (!e.getMessage().startsWith("Clock moved backwards")) throw e;
TimeUnit.MILLISECONDS.sleep(estimateCatchUpMs(e)); // or wait via monitoring
id = UUIDUtils.getInstance().getGeneratedKey();
} Defensive patterns
Strategy: try-catch
Validate before calling
// before generating: check clock is not behind a previously persisted max timestamp
long last = loadLastPersistedTimestamp();
if (System.currentTimeMillis() < last) {
throw new IllegalStateException("Clock behind last issued id timestamp by " + (last - System.currentTimeMillis()) + " ms");
} Try / catch
try {
long id = UUIDUtils.getInstance().getGeneratedKey();
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Clock moved backwards")) {
// wait/retry after clock re-sync
} else {
throw e;
}
} Prevention
- 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)
When it happens
Trigger: Calling UUIDUtils.getInstance().getGeneratedKey() (or any ID-generation path) after the JVM clock jumps backwards relative to the last timestamp recorded in nextId().
Common situations: 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.
Related errors
- worker Id can't be greater than
- datacenter Id can't be greater than
- we not support metric registration for type
- WASI proc_exit( ) from
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/6825cc9b8ae32dab.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-common/src/main/java/org/apache/shenyu/common/utils/UUIDUtils.java:87
}
this.workerId = workerId;
this.datacenterId = datacenterId;
this.idepoch = idepoch;
}
/**
* Gets instance.
*
* @return the instance
*/
public static UUIDUtils getInstance() {
return ID_WORKER_UTILS;
}
private synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & SEQUENCE_MASK;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - idepoch) << TIMESTAMP_LEFT_SHIFT)
| (datacenterId << DATACENTER_ID_SHIFT)
| (workerId << WORKER_ID_SHIFT) | sequence;
}
private long tilNextMillis(final long lastTimestamp) {View on GitHub (pinned to 567142e072)