From 75811ef1fe7390125eec27eea3eab2be294a1ab9 Mon Sep 17 00:00:00 2001 From: Zihan Dai <99155080+PDGGK@users.noreply.github.com> Date: Sat, 15 Aug 2026 18:48:21 +1000 Subject: [PATCH] fix(services/lakefs): follow the pagination cursor instead of stopping after one page The lister decodes LakefsListResponse -- whose Pagination carries has_more and next_offset -- and then sets ctx.done = true unconditionally. Both fields appear in the crate only in their own declarations at core.rs:319 and :321; nothing reads them. So a listing returns the first server page and reports success. Nothing errors, nothing warns; the caller simply receives fewer entries than exist. lakefs does not declare list_with_limit, so no &amount is sent and the server's own default page size applies, and recursive listing is emulated by driving this lister per directory, so every level truncates independently. The cursor is now fed back as after on later pages. The parameter already exists and the lister already sends the caller's start_after on the first page, so this only fills in the pages after it. The encoding belongs in the same change rather than a follow-up: core.rs:147 concatenated after raw, and next_offset is an object path chosen by the server. Driving the cursor is what makes a non-empty after reachable at all, so shipping one without the other would introduce exactly the defect #8073 fixed across five services -- a key with a space aborting the request, one with # silently rewinding the page. --- core/services/lakefs/src/core.rs | 2 +- core/services/lakefs/src/lister.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/services/lakefs/src/core.rs b/core/services/lakefs/src/core.rs index 579f2be07f67..b16ccb26e844 100644 --- a/core/services/lakefs/src/core.rs +++ b/core/services/lakefs/src/core.rs @@ -144,7 +144,7 @@ impl LakefsCore { } if let Some(after) = after { - url.push_str(&format!("&after={after}")); + url.push_str(&format!("&after={}", percent_encode_path(&after))); } let mut req = Request::get(&url); diff --git a/core/services/lakefs/src/lister.rs b/core/services/lakefs/src/lister.rs index c4e27f4ef354..51077a1ca3f7 100644 --- a/core/services/lakefs/src/lister.rs +++ b/core/services/lakefs/src/lister.rs @@ -64,11 +64,12 @@ impl oio::PageList for LakefsLister { &self.path, self.delimiter, &self.amount, - // start after should only be set for the first page. + // start_after applies to the first page; later pages resume from the + // cursor the previous response returned. if ctx.token.is_empty() { self.after.clone() } else { - None + Some(ctx.token.clone()) }, ) .await?; @@ -84,7 +85,9 @@ impl oio::PageList for LakefsLister { let decoded_response: LakefsListResponse = serde_json::from_reader(bytes.reader()).map_err(new_json_deserialize_error)?; - ctx.done = true; + let pagination = decoded_response.pagination; + ctx.done = !pagination.has_more; + ctx.token = pagination.next_offset; for status in decoded_response.results { let entry_type = match status.path_type.as_str() {