{"record":{"id":"860410b68c2e0e54","repo":"apache/rocketmq","slug":"seek-offset-illegal-seek-offset","errorCode":null,"errorMessage":"Seek offset illegal, seek offset = ","messagePattern":"Seek offset illegal, seek offset = ","errorType":"exception","errorClass":"MQClientException","httpStatus":null,"severity":"error","filePath":"client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java","lineNumber":677,"sourceCode":"        assignedMessageQueue.pause(messageQueues);\n    }\n\n    public void resume(Collection<MessageQueue> messageQueues) {\n        assignedMessageQueue.resume(messageQueues);\n    }\n\n    public synchronized void seek(MessageQueue messageQueue, long offset) throws MQClientException {\n        if (!assignedMessageQueue.getAssignedMessageQueues().contains(messageQueue)) {\n            if (subscriptionType == SubscriptionType.SUBSCRIBE) {\n                throw new MQClientException(\"The message queue is not in assigned list, may be rebalancing, message queue: \" + messageQueue, null);\n            } else {\n                throw new MQClientException(\"The message queue is not in assigned list, message queue: \" + messageQueue, null);\n            }\n        }\n        long minOffset = minOffset(messageQueue);\n        long maxOffset = maxOffset(messageQueue);\n        if (offset < minOffset || offset > maxOffset) {\n            throw new MQClientException(\"Seek offset illegal, seek offset = \" + offset + \", min offset = \" + minOffset + \", max offset = \" + maxOffset, null);\n        }\n        final Object objLock = messageQueueLock.fetchLockObject(messageQueue);\n        synchronized (objLock) {\n            clearMessageQueueInCache(messageQueue);\n\n            PullTaskImpl oldPullTaskImpl = this.taskTable.get(messageQueue);\n            if (oldPullTaskImpl != null) {\n                oldPullTaskImpl.tryInterrupt();\n                this.taskTable.remove(messageQueue);\n            }\n            assignedMessageQueue.setSeekOffset(messageQueue, offset);\n            if (!this.taskTable.containsKey(messageQueue)) {\n                PullTaskImpl pullTask = new PullTaskImpl(messageQueue);\n                this.taskTable.put(messageQueue, pullTask);\n                this.scheduledThreadPoolExecutor.schedule(pullTask, 0, TimeUnit.MILLISECONDS);\n            }\n        }\n    }","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/apache/rocketmq/blob/293f5885719fc4aa3619446a1900f58ccfcfdd29/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java#L659-L695","documentation":"seek() validates the requested offset against the queue's current [minOffset, maxOffset] range (queried from the broker) and throws this MQClientException when offset falls outside it. Seeking before the earliest retained offset or past the latest written offset would skip or replay data incorrectly, so it is rejected.","triggerScenarios":"seek(q, 0) when the earliest message has been deleted (minOffset advanced by retention); seek(q, Long.MAX_VALUE) intending 'end' — maxOffset is the last message offset, not last+1, so maxOffset is allowed but maxOffset+N is not.","commonSituations":"Seek-to-beginning on a topic whose old segments expired; hard-coding an offset captured days ago after retention deleted it; seeking to maxOffset+1 to go to tail.","solutions":["Query min/max first via consumer.minOffset(q)/maxOffset(q) and clamp: Math.min(Math.max(offset, min), max)","For seek-to-tail use maxOffset(q); for seek-to-head use minOffset(q) instead of literals","If an old offset expired, accept replay from minOffset"],"exampleFix":"// before\nconsumer.seek(queue, savedOffset);\n\n// after\nlong min = consumer.minOffset(queue), max = consumer.maxOffset(queue);\nlong target = Math.min(Math.max(savedOffset, min), max);\nconsumer.seek(queue, target);","handlingStrategy":"validation","validationCode":"long min = consumer.minOffset(q), max = consumer.maxOffset(q);\nlong target = Math.min(Math.max(desiredOffset, min), max);\nconsumer.seek(q, target);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hard-code offsets; always clamp against current min/max before seek","Use minOffset(q)/maxOffset(q) for head/tail seeks instead of 0/Long.MAX_VALUE"],"tags":["rocketmq","consumer","seek","offset","retention"],"backgroundTag":null,"analyzedSha":"293f5885719fc4aa3619446a1900f58ccfcfdd29","analyzedAt":"2026-08-14T11:50:13.822Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}