OrderedDataStore:GetSortedAsync() is not returning true on the last page.
This causes the while loop to run endlessly, causing rate limits.
Expected behavior
Pages.IsFinished to return true when the last page has been reached.
Repro Code
local orderedDS = game:GetService("DataStoreService"):GetOrderedDataStore("TestDS")
orderedDS:SetAsync("Test1", 10)
orderedDS:SetAsync("Test2", 1)
print("setted")
task.wait(5)
local pages = orderedDS:GetSortedAsync(true, 100)
while true do
local breaking = false
local page = pages:GetCurrentPage()
for _, data in ipairs(page) do
local key:string = data.key
local exist:number = data.value
print("key", key)
end
if pages.IsFinished then
-- We've reached the last page of results
breaking = true
else
-- There are more pages of results
pages:AdvanceToNextPageAsync()
print("advancing, IsFinished", pages.IsFinished)
end
if breaking then
break
end
end
It broke my game too, i spent lots of hours but couldnt find any solution. This literally zeroed my playerbase and still there isnt any update, I think this is a really critical issue and should be fixed like right now. I really wish engineers will fix it very soon
It seems like that this bug no longer occurrs on newly created ordered datastores even after saving 10,000 keys and then removing them however the bug still happens on old ordered datastores.
After investigating what the backend responds on a broken and a not broken datastore these are my findings:
Not Broken Ordered Datastore
Broken Ordered Datastore
The lastEvaluatedKey being an empty string is probably messing with robloxs check to determine if it IsFinished
local pageSize = 100
local ascending = false
local pages = OrderedDataStore:GetSortedAsync(ascending, pageSize)
local currentPage = pages:GetCurrentPage()
-- If the first page is empty, exit early (nothing to process)
if #currentPage == 0 then
return
end
local lastPageKeys = nil
while true do
-- Extract keys from the current page for comparison
local currentPageKeys = {}
for _, value in ipairs(currentPage) do
table.insert(currentPageKeys, value.Key)
end
-- Compare with the previous page (if it exists) to detect if we've reached the last page
if lastPageKeys then
local isSamePage = true
if #currentPageKeys == #lastPageKeys then
for i = 1, #currentPageKeys do
if currentPageKeys[i] ~= lastPageKeys[i] then
isSamePage = false
break
end
end
else
isSamePage = false
end
if isSamePage then
break -- Exit if the page hasn't changed (we're on the last page)
end
end
-- Process the current page
for index, value in ipairs(currentPage) do
-- your code here
end
-- Update lastPageKeys for the next iteration
lastPageKeys = currentPageKeys
-- If the current page has fewer items than pageSize, it's the last page.
-- (Note: if the page has exactly pageSize items, calling AdvanceToNextPageAsync will error if it is the last page.)
if #currentPage < pageSize then
break
end
-- Try advancing to the next page only once
local success, errorMessage = pcall(function()
pages:AdvanceToNextPageAsync()
end)
if not success then
print("AdvanceToNextPageAsync failed:", errorMessage)
break -- Consider it done if advancing fails
end
currentPage = pages:GetCurrentPage()
-- Exit if the new page is empty
if #currentPage == 0 then
break
end
end
I swear i thought i was going crazy when i encountered this bug
This is why I hate that the web uses javascript for everything. There’s all these arbitrary “falsy” things like that empty string that end up in places where they shouldn’t be, because somebody’s brain was still in JS mode thinking “oh yeah “” = false = null”, and then that formatting ends up breaking everything when getting ported to lua.