Skip to content

[CORE-16844] kafka/client: recover from offset_out_of_range in consumer group fetch#31064

Draft
bartoszpiekny-redpanda wants to merge 1 commit into
redpanda-data:devfrom
bartoszpiekny-redpanda:CORE-16844-fix-offset_out_of_range-after-retention
Draft

[CORE-16844] kafka/client: recover from offset_out_of_range in consumer group fetch#31064
bartoszpiekny-redpanda wants to merge 1 commit into
redpanda-data:devfrom
bartoszpiekny-redpanda:CORE-16844-fix-offset_out_of_range-after-retention

Conversation

@bartoszpiekny-redpanda

@bartoszpiekny-redpanda bartoszpiekny-redpanda commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Pandaproxy's consumer group fetch always started a fresh partition assignment at offset 0 and never advanced once retention moved the log start offset past it, regardless of auto.offset.reset=earliest requested at consumer creation. Every fetch after that point returned offset_out_of_range forever, since fetch_session::apply() silently discarded the error without correcting its tracked offset.

fetch_session::apply() now seeds the tracked offset from the log_start_offset reported alongside offset_out_of_range, since pandaproxy only ever allows the earliest reset policy. dispatch_fetch() throws once the offset has been corrected, so the existing gated_retry_with_mitigation retry in client::consumer_fetch() re-fetches with the corrected offset before returning to the REST client, which has no way to control the fetch offset itself.

Adds a fetch_session unit test covering the offset_out_of_range recovery, and a pandaproxy ducktape regression test that trims a topic's log prefix and asserts a fresh consumer group fetch still succeeds.

Fixes:

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v26.1.x
  • v25.3.x
  • v25.2.x

Release Notes

@bartoszpiekny-redpanda bartoszpiekny-redpanda force-pushed the CORE-16844-fix-offset_out_of_range-after-retention branch 2 times, most recently from 9ca82a8 to 2293be2 Compare July 10, 2026 10:48
@bartoszpiekny-redpanda bartoszpiekny-redpanda force-pushed the CORE-16844-fix-offset_out_of_range-after-retention branch from 2293be2 to 940d6dd Compare July 10, 2026 10:54
Pandaproxy's consumer group fetch always started a fresh partition
assignment at offset 0 and never advanced once retention moved the
log start offset past it, regardless of auto.offset.reset=earliest
requested at consumer creation. Every fetch after that point returned
offset_out_of_range forever, since fetch_session::apply() silently
discarded the error without correcting its tracked offset.

fetch_session::apply() now seeds the tracked offset from the
log_start_offset reported alongside offset_out_of_range, since
pandaproxy only ever allows the earliest reset policy. dispatch_fetch()
throws once the offset has been corrected, so the existing
gated_retry_with_mitigation retry in client::consumer_fetch() re-fetches
with the corrected offset before returning to the REST client, which
has no way to control the fetch offset itself.

Adds a fetch_session unit test covering the offset_out_of_range
recovery, and a pandaproxy ducktape regression test that trims a
topic's log prefix and asserts a fresh consumer group fetch still
succeeds.
@bartoszpiekny-redpanda bartoszpiekny-redpanda force-pushed the CORE-16844-fix-offset_out_of_range-after-retention branch from 940d6dd to eb5dd14 Compare July 10, 2026 12:06
@bartoszpiekny-redpanda bartoszpiekny-redpanda marked this pull request as ready for review July 10, 2026 12:21
Copilot AI review requested due to automatic review settings July 10, 2026 12:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Pandaproxy consumer-group fetch getting stuck returning offset_out_of_range after log retention/prefix-truncation advances a partition’s log start offset beyond the consumer’s initial fetch offset.

Changes:

  • Update fetch_session::apply() to seed the tracked fetch offset from log_start_offset when a partition returns offset_out_of_range.
  • Trigger a retry from the Kafka client consumer fetch path so Pandaproxy re-fetches using the corrected offset.
  • Add unit and ducktape regression tests covering prefix-trim recovery.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
tests/rptest/tests/pandaproxy_test.py Adds a ducktape regression test that trims a topic prefix and verifies a fresh consumer-group fetch still succeeds.
src/v/kafka/client/test/fetch_session.cc Adds a unit test ensuring fetch_session::apply() updates tracked offsets on offset_out_of_range.
src/v/kafka/client/fetch_session.cc Implements offset correction on offset_out_of_range using log_start_offset.
src/v/kafka/client/consumer.cc Throws on offset_out_of_range after applying the response to force a retry before returning to Pandaproxy.

Comment on lines 429 to +444
_fetch_sessions[broker].apply(res);

// Offset just corrected above; retry so the pandaproxy client, which
// can't control the fetch offset itself, never sees this error.
// Caught and retried by gated_retry_with_mitigation() in
// client::consumer_fetch.
auto it = std::find_if(res.begin(), res.end(), [](auto& part) {
return part.partition_response->error_code
== error_code::offset_out_of_range;
});
if (it != res.end()) {
throw partition_error(
model::topic_partition{
it->partition->topic, it->partition_response->partition_index},
error_code::offset_out_of_range);
}
@bartoszpiekny-redpanda bartoszpiekny-redpanda marked this pull request as draft July 10, 2026 12:47
@vbotbuildovich

vbotbuildovich commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Retry command for Build#86958

please wait until all jobs are finished before running the slash command

/ci-repeat 1
skip-redpanda-build
skip-units
skip-rebase
tests/rptest/tests/pandaproxy_test.py::PandaProxyConsumerGroupTest.test_consumer_group_fetch_after_prefix_trim

@vbotbuildovich

Copy link
Copy Markdown
Collaborator

CI test results

test results on build#86958
test_status test_class test_method test_arguments test_kind job_url passed reason test_history
FLAKY(PASS) DatalakeCustomPartitioningTest test_many_partitions {"catalog_type": "rest_jdbc", "cloud_storage_type": 1} integration https://buildkite.com/redpanda/redpanda/builds/86958#019f4c05-fcf1-4475-93fb-dfeedef9fe38 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0000, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=DatalakeCustomPartitioningTest&test_method=test_many_partitions
FAIL PandaProxyConsumerGroupTest test_consumer_group_fetch_after_prefix_trim null integration https://buildkite.com/redpanda/redpanda/builds/86958#019f4c05-fcf2-46b3-ba2c-cee09b854379 0/11 The test was found to be new, and no failures are allowed https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=PandaProxyConsumerGroupTest&test_method=test_consumer_group_fetch_after_prefix_trim
FAIL PandaProxyConsumerGroupTest test_consumer_group_fetch_after_prefix_trim null integration https://buildkite.com/redpanda/redpanda/builds/86958#019f4c06-23d8-4bff-b3c1-ec7712ea3e88 0/11 The test was found to be new, and no failures are allowed https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=PandaProxyConsumerGroupTest&test_method=test_consumer_group_fetch_after_prefix_trim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants