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

  1. Wait the reported number of milliseconds until the clock passes lastTimestamp, then retry.
  2. Ensure NTP uses gradual slewing instead of step changes on Mycat hosts.
  3. Persist/restore lastTimestamp on restart to detect regressions; never roll back VM snapshots for id-issuing nodes.
  4. 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

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


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)