fix: enforce project-level model-specific rate limits in parallel_req… - #25994
Conversation
…uest_limiter_v3
Project-level model rpm/tpm limits stored in project_metadata were never
checked during rate limit enforcement — only model-level limits applied.
Adds _add_project_model_rate_limit_descriptor_from_metadata() to the v3
limiter (mirrors the existing team metadata path) and calls it in
async_pre_call_hook, creating a model_per_project descriptor keyed as
"{project_id}:{model}" with the project's configured limits.
Also extends get_model_rate_limit_from_metadata's Literal to accept
"project_metadata" and adds get_project_model_rpm/tpm_limit helpers.
Fixes: LIT-2317
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR adds enforcement of project-level model-specific rate limits ( Confidence Score: 5/5Safe to merge — the pre-call descriptor and post-call TPM increment for model_per_project are both correctly implemented, mirroring the established team/org patterns. The previously flagged P1 concern (missing model_per_project TPM increment in the success handler) has been addressed in this PR at lines 1688–1696. All remaining notes (dead helper functions, redundant metadata lookups, project_id=None bucket) are in the previous threads and are P2-level at most, none blocking merge. No files require special attention; all critical paths are covered by the new tests.
|
| Filename | Overview |
|---|---|
| litellm/proxy/hooks/parallel_request_limiter_v3.py | Adds _add_project_model_rate_limit_descriptor_from_metadata for pre-call enforcement and adds model_per_project TPM increment in the success event pipeline; mirrors team/org patterns correctly. |
| litellm/proxy/auth/auth_utils.py | Extends get_model_rate_limit_from_metadata Literal type for project_metadata and adds get_project_model_rpm_limit / get_project_model_tpm_limit helpers (currently unused in the new method, which calls get_model_rate_limit_from_metadata directly). |
| tests/test_litellm/proxy/hooks/test_parallel_request_limiter_v3.py | Adds two regression tests for project-level model rate limits: one verifying descriptor creation, one verifying no descriptor for an unlisted model. Both are mock-only with no network calls. |
| tests/test_litellm/proxy/auth/test_auth_utils.py | Adds unit tests for get_project_model_rpm_limit, get_project_model_tpm_limit, and check_complete_credentials helpers — all mock-based with good coverage. |
Sequence Diagram
sequenceDiagram
participant Client
participant PreCallHook as async_pre_call_hook
participant Descriptor as _add_project_model_rate_limit_descriptor
participant RateLimiter as should_rate_limit
participant SuccessHook as _build_success_event_pipeline_operations
participant Redis
Client->>PreCallHook: request with project_metadata model limits
PreCallHook->>Descriptor: build descriptors
Descriptor->>Descriptor: get_model_rate_limit_from_metadata rpm
Descriptor->>Descriptor: get_model_rate_limit_from_metadata tpm
Descriptor-->>PreCallHook: RateLimitDescriptor model_per_project
PreCallHook->>RateLimiter: check all descriptors
RateLimiter-->>PreCallHook: OK or 429
PreCallHook-->>Client: proceed or rate limited
Client->>SuccessHook: on success with token usage
SuccessHook->>Redis: increment model_per_project tokens counter
Reviews (7): Last reviewed commit: "Merge remote-tracking branch 'upstream/l..." | Re-trigger Greptile
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 29203065 | Triggered | JSON Web Token | a449fc1 | tests/test_litellm/proxy/test_litellm_pre_call_utils.py | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
…lete_credentials Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@greptile review again |
Without this, project-level model_tpm_limit was silently acting as an RPM cap — the pre-call +1 sentinel was tracked but the actual token count was never added after a successful call. Extracts user_api_key_project_id from standard_logging_metadata and adds a model_per_project pipeline operation matching the existing model_per_team and model_per_organization patterns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@greptile review with the new commit |
…uest_limiter_v3 Move async_log_success_event pipeline construction into _build_success_event_pipeline_operations so the async hook stays under Ruff's max-statement limit. Made-with: Cursor
… litellm_project_rate_limiting
63313bc
into
litellm_internal_staging
…miting fix: enforce project-level model-specific rate limits in parallel_req…
Root Cause
Project-level model-specific rate limits (model_rpm_limit / model_tpm_limit stored
in project_metadata) were never checked during rate limit enforcement. The
parallel_request_limiter_v3.py had descriptor creation for team and organization
model limits, but nothing for projects.
Changes Made
litellm/proxy/auth/auth_utils.py
"project_metadata"
(mirrors the existing team equivalents)
litellm/proxy/hooks/parallel_request_limiter_v3.py
_add_team_model_rate_limit_descriptor_from_metadata but reads from project_metadata
and creates a "model_per_project" descriptor keyed as "{project_id}:{model}"
tests/test_litellm/proxy/hooks/test_parallel_request_limiter_v3.py
descriptor is created with correct rpm/tpm values
no descriptor is created when the requested model isn't in the project's limit
config
Project level rpm 1
Before:

After:
