Skip to content

[Fix] /key/aliases: Add pagination and search to prevent OOMs - #22137

Merged
yuneng-jiang merged 5 commits into
mainfrom
litellm_key_info_crash_fix
Feb 26, 2026
Merged

[Fix] /key/aliases: Add pagination and search to prevent OOMs#22137
yuneng-jiang merged 5 commits into
mainfrom
litellm_key_info_crash_fix

Conversation

@yuneng-jiang

@yuneng-jiang yuneng-jiang commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

Summary

The `/key/aliases` endpoint previously fetched all key aliases from the database without limit, causing out-of-memory crashes with large key sets. This fix adds pagination and search parameters to the endpoint, moving filtering and pagination to the database level.

Changes

Added `page`, `size`, and `search` query parameters to `/key/aliases`. Replaced the unbounded database query with `count` + `find_many` using `skip`/`take` and case-insensitive `contains` filtering via Prisma. Added `select={"key_alias": True}` so only the alias column is fetched instead of full token rows. Response now includes pagination metadata (`total_count`, `current_page`, `total_pages`, `size`) matching the `/v2/model/info` pattern. Added five unit tests in `tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py` covering response shape, pagination, search filter injection, and the select-only-alias optimization.

Type

🐛 Bug Fix
✅ Test

The /key/aliases endpoint previously fetched all key aliases from the database without limit, causing OOM crashes with large key sets. Added page, size, and search query parameters with database-level filtering to enable paginated and searchable key alias retrieval. Updated the response to include pagination metadata (total_count, current_page, total_pages, size) matching the /v2/model/info pattern.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Feb 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Feb 26, 2026 6:07pm

Request Review

@greptile-apps

greptile-apps Bot commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes an OOM risk in the /key/aliases endpoint by replacing an unbounded Prisma ORM query (which loaded full token rows into memory) with paginated raw SQL that selects only the key_alias column. The endpoint now accepts page, size, and search query parameters, returning pagination metadata alongside the alias list.

  • Replaced find_many with raw SQL using parameterized LIMIT/OFFSET and SELECT key_alias to minimize memory usage
  • Added case-insensitive ILIKE search support with properly parameterized queries (no SQL injection risk)
  • Response now includes total_count, current_page, total_pages, and size fields matching the /v2/model/info pagination pattern
  • Updated existing integration tests and added 4 new mock-based unit tests covering response shape, pagination math, and search filtering
  • Minor note: ILIKE wildcard characters (%, _) in search input are not escaped, which could cause unexpected match behavior

Confidence Score: 4/5

  • This PR is safe to merge — it fixes a real OOM issue with correct parameterized SQL and good test coverage.
  • The core change is well-implemented: parameterized queries prevent SQL injection, the index arithmetic for LIMIT/OFFSET is correct, and the raw SQL approach addresses the previous review feedback about fetching full rows. The only minor issue is unescaped ILIKE wildcards in the search input, which is a style/correctness concern rather than a security or correctness blocker.
  • litellm/proxy/management_endpoints/key_management_endpoints.py — verify ILIKE wildcard escaping behavior is acceptable for your use case.

Important Files Changed

Filename Overview
litellm/proxy/management_endpoints/key_management_endpoints.py Replaces unbounded ORM query with paginated raw SQL using parameterized queries. Correctly computes parameter indices for LIMIT/OFFSET. Minor issue: ILIKE wildcard chars in search input are not escaped.
tests/proxy_unit_tests/test_key_generate_prisma.py Updated existing integration tests to match new paginated response shape and added search parameter test cases.
tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py Added 4 mock-based unit tests covering response shape, pagination math, ILIKE search filtering, and no-search case. All tests use AsyncMock (no real network calls).

Sequence Diagram

sequenceDiagram
    participant Client
    participant KeyAliasesEndpoint as /key/aliases
    participant PostgreSQL as PostgreSQL DB

    Client->>KeyAliasesEndpoint: GET /key/aliases?page=1&size=50&search=my-key
    KeyAliasesEndpoint->>PostgreSQL: SELECT COUNT(*) ... WHERE key_alias ILIKE $2
    PostgreSQL-->>KeyAliasesEndpoint: total_count
    KeyAliasesEndpoint->>PostgreSQL: SELECT key_alias ... WHERE key_alias ILIKE $2 LIMIT $3 OFFSET $4
    PostgreSQL-->>KeyAliasesEndpoint: alias rows (key_alias only)
    KeyAliasesEndpoint-->>Client: { aliases, total_count, current_page, total_pages, size }
Loading

Last reviewed commit: 386c148

@greptile-apps greptile-apps Bot 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.

3 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 4153 to 4158
rows = await prisma_client.db.litellm_verificationtoken.find_many(
where=where,
order=[{"key_alias": "asc"}],
skip=(page - 1) * size,
take=size,
)

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.

Fetching full rows when only key_alias is needed

This query fetches all columns of LiteLLM_VerificationToken (which includes large fields like metadata, permissions, etc.) when only key_alias is needed. Since this endpoint is specifically designed to prevent OOM issues, consider using Prisma's include or restructuring to only retrieve the key_alias column. With large key sets, retrieving full rows at page size 100 may still use significantly more memory than necessary.

Add select={"key_alias": True} to the find_many call so only the alias
column is fetched from the database instead of full token rows. Add
five unit tests in test_key_management_endpoints.py covering response
shape, pagination skip/take computation, search filter injection,
absence of contains filter when no search term is given, and the
select-only-alias optimization.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@yuneng-jiang

Copy link
Copy Markdown
Contributor Author

@greptile

LiteLLM_VerificationTokenActions.find_many() does not support the
select keyword argument. Remove it and drop the corresponding test.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Replace Prisma ORM count/find_many calls with two query_raw calls that
only project the key_alias column. The Prisma client wrapper does not
support SELECT projection via find_many, so raw SQL is used to keep
memory usage proportional to the page size rather than total key count.
Update tests to mock query_raw instead of count/find_many.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@yuneng-jiang

Copy link
Copy Markdown
Contributor Author

@greptile

@greptile-apps

greptile-apps Bot commented Feb 26, 2026

Copy link
Copy Markdown
Contributor
Additional Comments (1)

litellm/proxy/management_endpoints/key_management_endpoints.py, line 4150
ILIKE wildcards in search input are not escaped

If a user passes a search string containing SQL ILIKE wildcard characters (% or _), they will be interpreted literally by PostgreSQL as wildcards rather than as literal characters. For example, searching for "my_key" would match "my-key", "myXkey", etc., because _ matches any single character in ILIKE patterns.

Consider escaping these characters before wrapping with %:

            escaped = search.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
            query_params.append(f"%{escaped}%")

yuneng-jiang added a commit that referenced this pull request Feb 26, 2026
Replace the non-paginated Key Alias filter with a new PaginatedKeyAliasSelect component that mirrors the existing PaginatedModelSelect pattern. This aligns the UI with the paginated /key/aliases endpoint from PR #22137.

Changes:
- Added useInfiniteKeyAliases hook for paginated key alias fetching
- Created PaginatedKeyAliasSelect component with infinite scroll (80% threshold)
- Updated keyAliasesCall in networking to accept page/size/search params
- Replaced Key Alias filter in Request Logs and Virtual Keys tables to use customComponent
- Removed fetchAllKeyAliases helper and related upfront fetching logic
- Added 22 tests for new component and hook; all existing tests pass (54 tests)

Fixes the issue where the UI was fetching all key aliases at once, causing performance issues with large key sets.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@yuneng-jiang
yuneng-jiang merged commit 50bf2da into main Feb 26, 2026
79 of 93 checks passed
Sameerlite pushed a commit that referenced this pull request Mar 3, 2026
Replace the non-paginated Key Alias filter with a new PaginatedKeyAliasSelect component that mirrors the existing PaginatedModelSelect pattern. This aligns the UI with the paginated /key/aliases endpoint from PR #22137.

Changes:
- Added useInfiniteKeyAliases hook for paginated key alias fetching
- Created PaginatedKeyAliasSelect component with infinite scroll (80% threshold)
- Updated keyAliasesCall in networking to accept page/size/search params
- Replaced Key Alias filter in Request Logs and Virtual Keys tables to use customComponent
- Removed fetchAllKeyAliases helper and related upfront fetching logic
- Added 22 tests for new component and hook; all existing tests pass (54 tests)

Fixes the issue where the UI was fetching all key aliases at once, causing performance issues with large key sets.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@ishaan-berri
ishaan-berri deleted the litellm_key_info_crash_fix branch March 26, 2026 22:29
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
Replace the non-paginated Key Alias filter with a new PaginatedKeyAliasSelect component that mirrors the existing PaginatedModelSelect pattern. This aligns the UI with the paginated /key/aliases endpoint from PR BerriAI#22137.

Changes:
- Added useInfiniteKeyAliases hook for paginated key alias fetching
- Created PaginatedKeyAliasSelect component with infinite scroll (80% threshold)
- Updated keyAliasesCall in networking to accept page/size/search params
- Replaced Key Alias filter in Request Logs and Virtual Keys tables to use customComponent
- Removed fetchAllKeyAliases helper and related upfront fetching logic
- Added 22 tests for new component and hook; all existing tests pass (54 tests)

Fixes the issue where the UI was fetching all key aliases at once, causing performance issues with large key sets.
fzowl pushed a commit to fzowl/litellm that referenced this pull request Jun 24, 2026
[Fix] /key/aliases: Add pagination and search to prevent OOMs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant