MyCATApache/Mycat-Server · 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
Snowflake ids embed the generation timestamp; generating an id with a clock older than the last used timestamp could produce duplicates. nextId() detects timestamp regression and throws a RuntimeException refusing id generation for the delta milliseconds until the clock catches back up.
Solutions
- Wait the reported number of milliseconds until the clock passes lastTimestamp, then retry.
- Ensure NTP uses gradual slewing instead of step changes on Mycat hosts.
- Persist/restore lastTimestamp on restart to detect regressions; never roll back VM snapshots for id-issuing nodes.
- If frequent, switch to the ZK-based or DB-based sequence which does not depend on wall-clock monotonicity.
Example fix
// before
long id = handler.nextId("ORDERID"); // throws after clock rollback
// after
try {
long id = handler.nextId("ORDERID");
} catch (RuntimeException e) {
Thread.sleep(parseRefusalMs(e.getMessage())); // wait out the regression
long id = handler.nextId("ORDERID");
} Defensive patterns
Strategy: retry
Validate before calling
// caller-side check
if (System.currentTimeMillis() < lastKnownTimestamp) { /* clock regression detected: pause id generation */ } Try / catch
try { id = handler.nextId(prefix); } catch (RuntimeException e) {
Thread.sleep(waitMsFromMessage(e.getMessage())); // wait out refusal window
id = handler.nextId(prefix);
} Prevention
- Configure NTP with slewing, not stepping, on id-generating nodes
- Avoid VM snapshot restores on id-issuing hosts
- Monitor clock offsets (chrony/ntpd) and alert on regressions
- Consider ZK/DB sequences where clock monotonicity cannot be guaranteed
When it happens
Trigger: nextId() called when timeGen() returns a value less than lastTimestamp, i.e. the system clock was set backwards (NTP correction, VM snapshot rollback, manual time change).
Common situations: NTP stepping the clock back on a busy id-generating node; restoring a VM from a snapshot; container migrated to a host with an earlier clock.
Related errors
- datacenter Id can't be greater than
- worker Id can't be greater than
- A batchSize of: with batchStatsAt of: will overrun the…
- Array has wrong size:
- Both batchStartsAt and batchSize must be positive but got…
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/c8fbe099b2126c50.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/route/sequence/handler/SnowflakeIdSequenceHandler.java:102
}
public SnowflakeIdSequenceHandler(long workerId) {
this(workerId, 13);
}
// 默认
public SnowflakeIdSequenceHandler() {
this(23, 13);
}
@Override
public synchronized long nextId(String prefixName) {
long timestamp = this.timeGen();
if (timestamp < this.lastTimestamp) {
logger.error(
"clock is moving backwards. Rejecting requests until %d.",
lastTimestamp);
throw new RuntimeException(
String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds",
(this.lastTimestamp - timestamp)));
}
if (this.lastTimestamp == timestamp) {
this.sequence = this.sequence + 1 & this.sequenceMask;
if (this.sequence == 0) {
timestamp = this.tilNextMillis(this.lastTimestamp);
}
} else {
this.sequence = 0;
}
this.lastTimestamp = timestamp;
return timestamp - this.twepoch << this.timestampLeftShift
| this.datacenterId << this.datacenterIdShift
| this.workerId << this.workerIdShift | this.sequence;
}View on GitHub (pinned to 65f8d8beb7)