---
title: "OffsetOutOfRangeException in Kafka: causes and fixes"
description: "Why a Kafka consumer fetch gets OFFSET_OUT_OF_RANGE after retention deletes its position, what auto.offset.reset does then, and how to recover a stuck group."
url: https://monedula.dev/kafka-simulator/troubleshooting/offset-out-of-range/
---

# OffsetOutOfRangeException (OFFSET_OUT_OF_RANGE)

Kafka error · OFFSET_OUT_OF_RANGE · not retriable.

Exception: `org.apache.kafka.clients.consumer.OffsetOutOfRangeException`

## Quick answer

The consumer asked for an offset the partition no longer has, almost always because retention deleted it while the consumer was behind or offline. With a reset policy the consumer jumps to the earliest or latest offset and the deleted records are skipped; only with auto.offset.reset=none does poll() throw OffsetOutOfRangeException, "Fetch position FetchPosition{offset=0, ...} is out of range for partition orders-0".

## What it means

A partition holds offsets from its log start offset to its log end. Retention (retention.ms, retention.bytes) deletes whole old segments and moves the log start forward. A fetch from an offset outside that range gets OFFSET_OUT_OF_RANGE (error code 1), and the consumer applies auto.offset.reset: earliest seeks to the log start, latest (the default) to the log end, by_duration (for example by_duration:P1D) to the offset that far back in time. It logs "Fetch position FetchPosition{offset=0, ...} is out of range for partition orders-0, resetting offset", and once it has looked up the new position, "Resetting offset for partition orders-0 to position FetchPosition{offset=1200, ...}." With none it logs "raising error to the application since no reset policy is configured" and poll() throws org.apache.kafka.clients.consumer.OffsetOutOfRangeException; the protocol error itself maps to org.apache.kafka.common.errors.OffsetOutOfRangeException. When retention caused it, the deleted records are gone for good: the group never processed them. A group with no committed offset at all, for example after offsets.retention.minutes removed it, is a different case: with none it fails with NoOffsetForPartitionException instead.

## Likely causes, most common first

1. **The consumer fell behind retention.** Lag grew past retention.ms (7 days by default) or retention.bytes: a slow consumer, a backlog after an outage, or retention lowered to save disk. Retention removes a segment file at a time, so the cut-off moves in steps rather than record by record.
2. **The group was offline longer than retention.** The committed offset stays where the group stopped. When the group returns after the segments holding that offset were deleted, its first fetch is out of range. Scenarios 05.1.1 (reset to earliest) and 05.1.3 (auto.offset.reset=none, group stuck) show both outcomes.
3. **Total retention passed on a tiered topic.** With tiered storage, a segment is copied to the remote tier once it rolls, and local.retention.ms only deletes the local copy, so a lagging consumer can still read it from the remote tier. retention.ms and retention.bytes delete from the remote tier too, and only that deletion makes an old offset out of range, as scenario 05.3.3 shows.
4. **The application seeks to an offset that does not exist.** consumer.seek() to a hard-coded value, to an offset stored outside Kafka, or to one taken from another topic or cluster asks for a position the partition never had or no longer has.

## How to fix it

- Measure how far behind the group is before it falls off the log: kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group my-group prints CURRENT-OFFSET, LOG-END-OFFSET and LAG per partition, and the consumer metric records-lag-max tracks it continuously.
- Compare the group's position with the log start: kafka-get-offsets.sh --bootstrap-server localhost:9092 --topic orders --time earliest prints each partition's earliest offset.
- Choose auto.offset.reset on purpose. latest, the default, skips every record still in the log, not only the deleted ones; earliest re-reads everything that survived; none stops the consumer so a person decides.
- To move a stuck group, stop its consumers, then run kafka-consumer-groups.sh --bootstrap-server localhost:9092 --reset-offsets --group my-group --topic orders --to-earliest (or --to-datetime, --by-duration) first with --dry-run and then with --execute.
- Give the topic a retention that covers the longest outage you plan for plus the time to catch up, and alert on lag before it reaches that window.

## What not to do

- Treating the "resetting offset" log line as noise: each one marks records the group skipped.
- Fixing a stuck auto.offset.reset=none group by switching it to latest without checking what is still in the log.

## Does the client retry it?

Not as such. With auto.offset.reset set to earliest, latest or by_duration, the consumer resets its position and fetches again without raising anything. With auto.offset.reset=none, poll() keeps throwing until the application seeks to a valid offset or an operator resets the group's offsets.

## Configs involved

- [`auto.offset.reset`](https://kafka.apache.org/43/configuration/consumer-configs/#consumerconfigs_auto.offset.reset): Where a consumer starts when its group has no committed offset or the offset no longer exists: latest (the default), earliest, by_duration (a time back from now, such as by_duration:PT1H), or none to throw an exception instead.
- [`retention.ms`](https://kafka.apache.org/43/configuration/topic-configs/#topicconfigs_retention.ms): How long a topic with cleanup.policy=delete keeps a log segment before it may be deleted (default 604800000, 7 days); -1 removes the time limit.
- [`retention.bytes`](https://kafka.apache.org/43/configuration/topic-configs/#topicconfigs_retention.bytes): The size a partition may grow to before its oldest segments are deleted under cleanup.policy=delete (default -1, no size limit); the limit is per partition, not per topic.
- [`local.retention.ms`](https://kafka.apache.org/43/configuration/topic-configs/#topicconfigs_local.retention.ms): On a tiered-storage topic, how long a segment stays on the broker disk once it has been copied to remote storage (default -2, which means retention.ms); the data stays readable from the remote tier until retention.ms removes it.
- [`offsets.retention.minutes`](https://kafka.apache.org/43/configuration/broker-configs/#brokerconfigs_offsets.retention.minutes): How long the group coordinator keeps the committed offsets of a group with no members, or of a partition the group no longer subscribes to (default 10080, 7 days); after that the group starts again from auto.offset.reset.

## Reproduce it in the simulator

- [Kafka retention.ms and a consumer that falls behind](https://monedula.dev/kafka-simulator/scenarios/time-retention/) (Time-based retention (retention.ms)): [open at the moment it happens](https://monedula.dev/kafka-simulator/playground/?scenario=05.1.1&t=3)
- [Kafka OFFSET_OUT_OF_RANGE with auto.offset.reset=none](https://monedula.dev/kafka-simulator/scenarios/offset-out-of-range/) (Offset out of range): [open at the moment it happens](https://monedula.dev/kafka-simulator/playground/?scenario=05.1.3&t=2)
- [Kafka local.retention.ms vs retention.ms in tiered storage](https://monedula.dev/kafka-simulator/scenarios/local-vs-total-retention/) (Local vs total retention): [open at the moment it happens](https://monedula.dev/kafka-simulator/playground/?scenario=05.3.3&t=6)

## Sources

- [Apache Kafka 4.3: consumer config auto.offset.reset](https://kafka.apache.org/43/configuration/consumer-configs/#consumerconfigs_auto.offset.reset)
- [Apache Kafka 4.3: topic config retention.ms](https://kafka.apache.org/43/configuration/topic-configs/#topicconfigs_retention.ms)
- [Apache Kafka 4.3: topic config retention.bytes](https://kafka.apache.org/43/configuration/topic-configs/#topicconfigs_retention.bytes)
- [Apache Kafka 4.3: broker config offsets.retention.minutes](https://kafka.apache.org/43/configuration/broker-configs/#brokerconfigs_offsets.retention.minutes)
- [Apache Kafka 4.3 Javadoc: org.apache.kafka.clients.consumer.OffsetOutOfRangeException](https://kafka.apache.org/43/javadoc/org/apache/kafka/clients/consumer/OffsetOutOfRangeException.html)
- [Apache Kafka 4.3.0 source: Errors.java (OFFSET_OUT_OF_RANGE, code 1)](https://github.com/apache/kafka/blob/4.3.0/clients/src/main/java/org/apache/kafka/common/protocol/Errors.java)
- [Apache Kafka 4.3.0 source: FetchCollector.java (reset or raise on OFFSET_OUT_OF_RANGE)](https://github.com/apache/kafka/blob/4.3.0/clients/src/main/java/org/apache/kafka/clients/consumer/internals/FetchCollector.java)
- [Apache Kafka 4.3: checking consumer position and managing consumer groups](https://kafka.apache.org/43/operations/basic-kafka-operations/#managing-consumer-groups)
- [Apache Kafka 4.3.0 source: GetOffsetShell.java (kafka-get-offsets.sh --time)](https://github.com/apache/kafka/blob/4.3.0/tools/src/main/java/org/apache/kafka/tools/GetOffsetShell.java)
- [Apache Kafka 4.3: tiered storage](https://kafka.apache.org/43/operations/tiered-storage/)
- [Apache Kafka 4.3.0 source: SubscriptionState.java (Resetting offset for partition)](https://github.com/apache/kafka/blob/4.3.0/clients/src/main/java/org/apache/kafka/clients/consumer/internals/SubscriptionState.java)

## Related

- [Why does a Kafka consumer reprocess messages after restart?](https://monedula.dev/kafka-simulator/troubleshooting/consumer-reprocesses-messages-after-restart/)
- [Kafka consumer lag keeps growing: causes and fixes](https://monedula.dev/kafka-simulator/troubleshooting/consumer-lag-keeps-growing/)
