apache/rocketmq · error · RuntimeException
Can't accept data with small epoch %d < %d
Error message
Can't accept data with small epoch %d < %d
What it means
TopicQueueMappingManager.updateTopicQueueMapping (non-force path) rejects new mapping metadata whose epoch is smaller than the currently stored epoch. Epochs monotonically increase for static-topic queue mappings; a lower epoch indicates stale/regressed metadata and is refused with RuntimeException.
Source
Thrown at broker/src/main/java/org/apache/rocketmq/broker/topic/TopicQueueMappingManager.java:106
oldDetail = topicQueueMappingTable.get(newDetail.getTopic());
if (oldDetail == null) {
topicQueueMappingTable.put(newDetail.getTopic(), newDetail);
updated = true;
return;
}
if (force) {
//bakeup the old items
oldDetail.getHostedQueues().forEach((queueId, items) -> {
newDetail.getHostedQueues().putIfAbsent(queueId, items);
});
topicQueueMappingTable.put(newDetail.getTopic(), newDetail);
updated = true;
return;
}
//do more check
if (newDetail.getEpoch() < oldDetail.getEpoch()) {
throw new RuntimeException(String.format("Can't accept data with small epoch %d < %d", newDetail.getEpoch(), oldDetail.getEpoch()));
}
if (!newDetail.getScope().equals(oldDetail.getScope())) {
throw new RuntimeException(String.format("Can't accept data with unmatched scope %s != %s", newDetail.getScope(), oldDetail.getScope()));
}
boolean epochEqual = newDetail.getEpoch() == oldDetail.getEpoch();
for (Integer globalId : oldDetail.getHostedQueues().keySet()) {
List<LogicQueueMappingItem> oldItems = oldDetail.getHostedQueues().get(globalId);
List<LogicQueueMappingItem> newItems = newDetail.getHostedQueues().get(globalId);
if (newItems == null) {
if (epochEqual) {
throw new RuntimeException("Cannot accept equal epoch with null data");
} else {
newDetail.getHostedQueues().put(globalId, oldItems);
}
} else {
TopicQueueMappingUtils.makeSureLogicQueueMappingItemImmutable(oldItems, newItems, epochEqual, isClean);
}
}View on GitHub (pinned to 293f588571)
Solutions
- Get the current mapping (getTopicQueueMapping / controller state) and resubmit with a strictly greater epoch.
- If you must override intentionally, use the force flag/path (admin force update), understanding it backfills old items.
- Align controller cluster state — a single source must allocate epochs; check for split-brain or stale controller instances.
Example fix
// before mqadmin updateTopicQueueMapping -n ns:9876 -t TopicA --epoch 3 // current epoch is 5 -> rejected // after mqadmin updateTopicQueueMapping -n ns:9876 -t TopicA --epoch 6 // strictly greater than current
Defensive patterns
Strategy: validation
Validate before calling
TopicQueueMappingDetail old = manager.queryTopicQueueMapping(topic);
if (old != null && newDetail.getEpoch() <= old.getEpoch()) {
newDetail.setEpoch(old.getEpoch() + 1); // or abort
} Type guard
boolean epochAcceptable(TopicQueueMappingDetail oldD, TopicQueueMappingDetail newD) {
return oldD == null || newD.getEpoch() >= oldD.getEpoch();
} Try / catch
catch (RuntimeException e) { if (e.getMessage().contains("small epoch")) { fetchCurrentMapping(); bumpEpoch(); resubmit(); } else throw e; } Prevention
- Always fetch the current mapping and use currentEpoch + 1 on updates.
- Let a single controller cluster own epoch allocation; don't hand-edit epochs.
When it happens
Trigger: A controller/name-server request to update the topic-queue mapping with an epoch lower than the broker's cached one — replayed/stale request, misconfigured controller epochs, or mixed-version controllers producing decreasing epochs.
Common situations: Request replay after timeout; controller restart losing epoch state; manual mqadmin mapping updates with explicit epochs lower than current; multiple controllers disagreeing.
Related errors
- Cannot accept equal epoch with null data
- Can't accept data with unmatched scope %s != %s
- Consumer group is not allowed to consume.
- datetime is null.
- User:{} is not found.
AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14).
Data as JSON: /api/errors/f45333411d04ca26.
Report an issue: GitHub.