fix(proxy): report has_more false on caller-scoped file list pages - #36326
Merged
mateo-berri merged 1 commit intoAug 9, 2026
Merged
Conversation
Contributor
Greptile SummaryThis PR corrects pagination metadata for caller-scoped managed-file listings so SDK auto-pagination terminates after the only reachable page.
Confidence Score: 5/5The PR appears safe to merge and correctly prevents auto-pagination from repeatedly requesting the same caller-scoped page. The changed metadata now reflects that no subsequent page is reachable through the proxy, while preserving the scoped data and rebuilt cursor identifiers; the regression test covers the previously failing non-empty-page case.
|
| Filename | Overview |
|---|---|
| enterprise/litellm_enterprise/proxy/hooks/managed_files.py | The scoped-page cursor helper now consistently clears has_more, matching the fact that pagination cursors are not forwarded upstream. |
| tests/enterprise/litellm_enterprise/proxy/hooks/test_managed_files.py | The existing owner-scoping test now verifies that an upstream has_more: true value is cleared on a non-empty scoped page. |
Reviews (1): Last reviewed commit: "fix(proxy): report has_more false on cal..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
tin-berri
approved these changes
Aug 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TLDR
Problem this solves:
has_more: trueHow it solves it:
has_more: falseUser Flow
Before: a user listing their files through the proxy with an auto-paginating OpenAI SDK client gets stuck receiving the same page of their own files forever
POST https://litellm-domain/key/generatePOST https://litellm-domain/v1/filesand gets managed file ids backGET https://litellm-domain/v1/filesand receives their files with"has_more": true, inherited from the shared upstream accountGET https://litellm-domain/v1/files?after=<last_id>, which returns the identical page with"has_more": trueagainAfter: the same listing finishes cleanly after one page
POST https://litellm-domain/key/generatePOST https://litellm-domain/v1/filesand gets managed file ids backGET https://litellm-domain/v1/filesand receives their files with"has_more": falseRelevant issues
Fixes #36324
Linear ticket
Pre-Submission checklist
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Two live proxies against real api.openai.com (real uploads, real account, no mocks), each in its own worktree with its own venv, its own empty postgres database, and its own port. Both legs drive the exact User Flow above with the OpenAI python SDK as the end-user client (base_url pointed at the proxy, api_key a freshly minted non-admin virtual key): mint the key via
POST /key/generate, upload two batch .jsonl files viaPOST /v1/fileswithtarget_model_names=gpt-5.4-nano, list, then auto-paginate. The loop precondition held on both legs: a direct controlGET https://api.openai.com/v1/filesreturned 5444 entries withhas_more: trueBefore, at
1f01f19457(the merge base, which already contains #36093)The owner's uploads minted
file-8pLa6rioZ1XC1BKWb7TE9jandfile-4eWQrLbGPbUp2Cz2ZKpT6rupstream, confirmed newest on the account by a direct control list. The owner's list through the proxy keeps the upstreamhas_more(2.99s wall, so the upstream page was really fetched and scoped):Following the cursor returns the identical page:
The real OpenAI python SDK auto-paginating over it never terminates:
The SDK refetched the same 2-item page five times, yielding the owner's 2 files over and over until the cap: the endless-duplicates loop from #36324
After, at
82662dc104(this branch's tip)Same flow, fresh uploads (
file-TxYAoJf9KEsqSxyN3DaiRH,file-9SFcxmSteqbL6M9Ah6SsJCupstream). The direct upstream control still reportedhas_more: truewith the owner's fresh upload as itsfirst_id, and the scoped page now reports false (3.7s wall):The same SDK script completes naturally:
The #36093 empty-page behavior is intact, checked with a second key on a different user_id and team:
Both legs deleted their uploads through the proxy afterwards and verified 404 on direct retrieves straight from api.openai.com, leaving the real account as found
Two observations from the runs, both pre-existing and left alone by this PR:
DELETE /v1/files/{managed_id}through the proxy responds with the managed file-object shape carrying"deleted": nullrather than OpenAI's{"deleted": true}confirmation shape even though the upstream delete really happens, and the shared QA account reportshas_more: trueon a full direct list of 5444 entries, so the loop precondition is the account's steady state rather than an over-10,000-files edge caseType
🐛 Bug Fix
Changes
The cursor-scoping applied to file list pages, added in #36093, cleared
has_moreonly when the caller's page came back empty, so a non-empty scoped page kept whatever the shared upstream account reported. Since theafterparameter is never forwarded upstream, no later page is ever reachable through the proxy, andhas_more: truesent OpenAI SDK auto-pagination into an endless loop over the identical page. The scoping now clearshas_moreon every page it touchesThe owner-page regression test now feeds an upstream page with
has_more: trueand asserts the scoped page reportsfalse; it fails without the one-line changeFinal Attestation