{"record":{"id":"1d3ff983f3d12a58","repo":"apache/druid","slug":"record-sequencenumber-s-is-smaller-than-current","errorCode":null,"errorMessage":"Record sequenceNumber[%s] is smaller than current sequenceNumber[%s] for partition[%s]","messagePattern":"Record sequenceNumber\\[(.+?)\\] is smaller than current sequenceNumber\\[(.+?)\\] for partition\\[(.+?)\\]","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunner.java","lineNumber":2236,"sourceCode":"   */\n  private boolean verifyRecordInRange(\n      final PartitionIdType partition,\n      final SequenceOffsetType recordOffset\n  )\n  {\n    // Verify that the record is at least as high as its currOffset.\n    final SequenceOffsetType currOffset = Preconditions.checkNotNull(\n        currOffsets.get(partition),\n        \"Current offset is null for partition[%s]\",\n        partition\n    );\n\n    final OrderedSequenceNumber<SequenceOffsetType> recordSequenceNumber = createSequenceNumber(recordOffset);\n    final OrderedSequenceNumber<SequenceOffsetType> currentSequenceNumber = createSequenceNumber(currOffset);\n\n    final int comparisonToCurrent = recordSequenceNumber.compareTo(currentSequenceNumber);\n    if (comparisonToCurrent < 0) {\n      throw new ISE(\n          \"Record sequenceNumber[%s] is smaller than current sequenceNumber[%s] for partition[%s]\",\n          recordOffset,\n          currOffset,\n          partition\n      );\n    }\n\n    // Check if the record has already been read.\n    if (isRecordAlreadyRead(partition, recordOffset)) {\n      return false;\n    }\n\n    // Finally, check if this record comes before the endOffsets for this partition.\n    return isMoreToReadBeforeReadingRecord(recordSequenceNumber.get(), endOffsets.get(partition));\n  }\n\n  /**\n   * checks if the input seqNum marks end of shard. Used by Kinesis only","sourceCodeStart":2218,"sourceCodeEnd":2254,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/SeekableStreamIndexTaskRunner.java#L2218-L2254","documentation":"SeekableStreamIndexTaskRunner.verifyProjectedOffsets compares the offset of an incoming record against the task's current (persisted) offset for the partition. Records from the stream must be at or after the current offset; a record whose sequence number is smaller than the current one means the stream is replaying already-processed data or offsets are corrupted, so the task throws an IllegalStateException instead of silently duplicating data.","triggerScenarios":"During addRecord/ingestion, recordOffset for partition is less than currOffset — e.g. after checkpoint restore the current offset is ahead of what the record supplier delivers, the topic/stream was reset to an earlier point, or records arrive out of order on a partition that isn't actually strictly ordered.","commonSituations":"Manually resetting Kafka offsets backward while a task is mid-run; using a non-earliest sequence number policy on Kinesis after resharding; corrupted checkpoints restored from backup; delivering records from a producer writing older offsets after a failover.","solutions":["Reset the supervisor (POST /druid/indexer/v1/supervisor/<id>/reset) so offsets are rebuilt consistently with the current stream position.","Restore/repair the task's persisted checkpoints so currOffset matches where the record supplier actually starts.","Ensure you never move source topic/stream offsets backward while tasks are running.","Verify partition ordering guarantees (single writer per partition, correct partition key) so records don't arrive with decreasing sequence numbers."],"exampleFix":"// before: source offsets reset backward under a running task\nkafka-consumer-groups.sh --reset-offsets --to-earliest ...\n// after: stop/reset supervisor first\ncurl -X POST 'http://overlord:8087/druid/indexer/v1/supervisor/my-supervisor/reset'","handlingStrategy":"validation","validationCode":"// ensure source offsets are never moved backward while a task runs\n// e.g. before resetting Kafka offsets: stop the supervisor first\ncurl -X POST http://overlord:8087/druid/indexer/v1/supervisor/<id>/suspend","typeGuard":null,"tryCatchPattern":"try { ingest(); } catch (ISE e) { if (e.getMessage().contains(\"is smaller than current sequenceNumber\")) { resetSupervisor(); } else { throw e; } }","preventionTips":["Never reset stream offsets backward under running tasks","Restore checkpoints only from consistent backups","Preserve per-partition ordering guarantees in producers"],"tags":["druid","kafka","kinesis","offsets","checkpoints"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}