Skip to content

chore(release): backport #27319, #27756, #27921, #28395, #29983, #29984, #29986, #30160, #30327 to stable/1.84.x and cut 1.84.8 - #30332

Merged
mateo-berri merged 14 commits into
stable/1.84.xfrom
litellm_backport_1_84_x_0612
Jun 13, 2026
Merged

chore(release): backport #27319, #27756, #27921, #28395, #29983, #29984, #29986, #30160, #30327 to stable/1.84.x and cut 1.84.8#30332
mateo-berri merged 14 commits into
stable/1.84.xfrom
litellm_backport_1_84_x_0612

Conversation

@yuneng-berri

@yuneng-berri yuneng-berri commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Relevant issues

Backport of seven staging fixes plus one prerequisite onto stable/1.84.x, cutting 1.84.8. Covers streaming Anthropic reasoning token usage, grace-period key rotation, native Azure container id routing, cached-plan recovery, DB-infra auth error semantics, and Anthropic pass-through cost resolution.

Grace-period rotation needed two changes: #27756 fixes the deprecated-key lookup itself, and #30327 (found while verifying this backport, fixed on staging first) completes the end-to-end flow. Both are included, so 1.84.8 carries the complete rotation fix.

What is included

Picks, in staging merge order, each with a (cherry picked from commit ...) footer:

Plus two test-only adaptation commits, the version bump to 1.84.8, and the uv.lock refresh.

Adaptation notes

Every production source file in every pick is patch-id identical to its staging counterpart, with one verified exception class:

Known noise on this line

Two pre-existing failures on the stable/1.84.x tip before any pick, unchanged after the picks: tests/test_litellm/proxy/test_proxy_utils.py::test_get_custom_url and tests/test_litellm/containers/test_azure_container_transformation.py::TestAzureContainerConfig::test_validate_environment_uses_azure_env_var (reads a real env var over the monkeypatched one in this environment).

Screenshots / Proof of Fix

Targeted test delta on this line: baseline 419 passed / 2 failed; after picks 520 passed / 2 failed; zero new failures, both failures are the pre-existing noise above.

Live proxy (this branch, port 4001), streaming Anthropic with reasoning_effort and include_usage:

# before picks
"completion_tokens_details":{"reasoning_tokens":0,"text_tokens":168}
# after picks, same request
"completion_tokens_details":{"reasoning_tokens":93,"text_tokens":84}

Anthropic pass-through on the generic route still costs correctly after the picks (no regression on the working path):

curl -s -X POST "http://localhost:4001/anthropic/v1/messages" -H "Authorization: Bearer <key>" \
  -H "anthropic-version: 2023-06-01" -d '{"model":"claude-haiku-4-5-20251001","max_tokens":64,"stream":true,...}'
# /key/info after spend flush
spend: 6e-05

The unknown-model costing path that produced $0 spend logs needs a router-passthrough deployment shape that does not register on this line's dev setup; behavior there is pinned by the six tests #30160 brings, which pass on this branch.

Grace-period rotation, end-to-end on a live proxy running this branch (key generated, regenerated with grace_period: "1h", then the OLD key used):

# before picks: every old-key call returned 401 (token_not_found_in_db)
# after picks (#27756 + #30327):
-- OLD key, call 1: HTTP 200
-- OLD key, call 2 (cache hit): HTTP 200
-- OLD key, call 3: HTTP 200
-- OLD key, real completion: "OK"
-- NEW key still works: HTTP 200

An adversarial multi-agent audit of the pick set (diff fidelity vs staging, symbol resolution, pick-test execution, and drifted-caller analysis) returned SURVIVED on all four sub-claims with zero verified refutations, fingerprinted at this branch's HEAD.

Type

🐛 Bug Fix

Changes

Ten cherry-picks onto stable/1.84.x as listed above, two test-only adaptation commits, version bump 1.84.7 -> 1.84.8, uv.lock refresh

ishaan-berri and others added 13 commits June 12, 2026 16:37
* fix anthropic streaming reasoning token usage

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

* test anthropic streaming reasoning usage end to end

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

* address anthropic reasoning token text split

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

* harden anthropic reasoning usage for mocked tokens

Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>

---------

Co-authored-by: oss-agent-shin <279349115+oss-agent-shin@users.noreply.github.com>
Co-authored-by: ishaan-berri <ishaan-berri@users.noreply.github.com>
(cherry picked from commit c15718f)
* fix(proxy): resolve cache handling issues in _lookup_deprecated_key

- Updated the in-memory cache for deprecated key lookups to store a 3-tuple (active_token_id, cache_expires_at_ts, revoke_at_ts) instead of a 2-tuple, ensuring proper unpacking and backward compatibility.
- Removed duplicate cache reads and added logic to handle legacy cache entries gracefully.
- Enhanced unit tests to cover scenarios for cache hits, DB misses, and respect for revoke_at timestamps, ensuring robust handling of the grace-period key-rotation feature.

* refactor(proxy): streamline cache handling in _lookup_deprecated_key

- Simplified the cache retrieval logic by directly unpacking the 3-tuple cache entries, removing the need for backward compatibility checks for 2-tuple entries.
- Updated unit tests to ensure that pre-warmed 3-tuple cache entries are served correctly without unnecessary database lookups.

* chore(ci): add new unit test for deprecated key grace period

- Included `test_deprecated_key_grace_period.py` in the CI workflow to enhance coverage for deprecated key handling scenarios.

* fix(proxy): remove unnecessary check for revoke_at in _lookup_deprecated_key

- Eliminated the redundant check for None on revoke_at, streamlining the logic for handling deprecated keys in the cache. This change enhances the efficiency of the key lookup process.

* test(proxy): add end-to-end tests for deprecated key lookup behavior

- Introduced a new test class `TestDeprecatedKeyLookupDbE2E` to validate the behavior of deprecated key lookups against a real Prisma-backed database.
- The test ensures that old key hashes resolve correctly and that repeated lookups utilize the in-memory cache without errors.
- Cleaned up the `_lookup_deprecated_key` function by removing an unnecessary check for `revoke_at`, enhancing the efficiency of the key lookup process.

(cherry picked from commit 8f25942)
…27921)

* fix(router): use forwarded model_id for native Azure container IDs in _init_containers_api_endpoints

Azure code-interpreter containers return provider-native IDs (cntr_ + hex)
that carry no LiteLLM routing payload, so _decode_container_id returns
model_id=None. The router was falling through to call the handler directly,
bypassing _ageneric_api_call_with_fallbacks and leaving api_base=None for
Azure deployments. Fall back to the model_id forwarded from the proxy
ownership check so deployment credentials are always applied.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(azure-containers): strip /openai/responses path from api_base in AzureContainerConfig.get_complete_url

When a deployment's api_base is the responses endpoint URL
(e.g. .../openai/responses?api-version=...), AzureContainerConfig was
appending /openai/containers on top of it, producing the broken path
.../openai/responses/openai/containers. Azure returns 404 for that URL
while the correct path is .../openai/containers.

Strip any /openai/responses suffix from api_base before constructing
the containers URL so the resource root is always used as the starting point.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(azure-containers): prefer api-version from api_base URL over deployment's api_version

The deployment's api_version (e.g. 2024-08-01-preview) targets the chat/responses
API and is too old for the containers API, which requires 2025-04-01-preview.
The responses endpoint api_base already carries the correct api-version in its
query string. Extract it and use it for the containers URL, overriding the
stale deployment-level version.

Fixes DELETE and file-upload operations returning 404 due to wrong api-version.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(containers): pass params=None instead of params={} to httpx to preserve api-version

httpx erases a URL's query-string when params={} (empty dict) is passed,
silently stripping ?api-version=2025-04-01-preview from every container
POST/DELETE request. Azure's GET endpoints tolerate a missing api-version;
POST (upload) and DELETE are strict, so those returned 404.

Fix: use `params or None` in container_handler._async_handle and
llm_http_handler.async_container_delete_handler (and all sibling container
handlers) so that an empty params dict falls back to None, leaving httpx to
preserve the URL's existing query string intact.

Adds a regression test that directly documents the httpx behaviour.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(router): remove elif model_id branch from _init_containers_api_endpoints

Two reviewer findings addressed:

1. Truncated comment on the model_id fallback line — now complete.

2. Security: the elif branch that fired when container_id was absent allowed
   any authenticated caller to supply model_id in a POST /v1/containers body
   and route the request through an arbitrary deployment UUID, bypassing the
   model-level access checks that only validate `model`. Removed the elif
   branch; operations without container_id (create, list) route by the
   caller-supplied `model` field as before. model_id forwarding is kept only
   inside the container_id block, where the proxy ownership check has already
   validated the container before forwarding the deployment ID.

Adds a regression test pinning the security boundary: no-container-id path
calls original_function directly even when model_id is in kwargs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(containers): validate proxy-to-router model_id forwarding for managed IDs

Add test_regression_get_container_forwarding_params_sets_model_id_for_managed_id
to verify that get_container_forwarding_params (the proxy-side half of the Azure
routing fix) correctly extracts and forwards model_id from a LiteLLM-managed
encoded container ID.

This closes the gap identified by Greptile P1: the previous regression test
only injected model_id as a direct kwarg, validating the router in isolation.
The new test exercises the actual proxy-to-router data flow through
ownership.get_container_forwarding_params, confirming that kwargs["model_id"]
is populated before _init_containers_api_endpoints is reached.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(azure-containers): tighten endpoint-path strip to endswith match

Use path.endswith() instead of path.find() for _AZURE_ENDPOINT_PATHS so
the suffix strip only fires when api_base actually ends with one of the
endpoint-specific path suffixes. This is the more precise check greptile
flagged on the original find()-based implementation.

* Fix sync container handler to preserve URL query string

Mirror the async path fix: pass None instead of an empty params dict so
httpx does not strip the URL's existing query string (e.g.
?api-version=...), which is required for Azure container routing.

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(azure-containers): strip trailing slash before endpoint suffix match

Co-authored-by: Yassin Kortam <yassin@berri.ai>

* fix(containers): recover model_id from stored encoded id for native Azure container IDs

get_container_forwarding_params previously only set model_id when the
user-supplied container_id was a LiteLLM-managed encoded id. For native
upstream IDs (e.g. Azure 'cntr_<hex>') the decode fails and model_id was
never forwarded — making the router-side fallback in
_init_containers_api_endpoints unreachable in production.

Fall back to the stored 'unified_object_id' on the ownership row, which
is the encoded form captured at create time when the router selected a
specific deployment. Decoding that yields the deployment model_id and
restores router-based credential application (api_base, api_key) for
retrieve/delete and container-file operations on native IDs.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Yassin Kortam <yassin@berri.ai>
(cherry picked from commit 7f563b2)
…28395)

* fix(proxy): expose Prisma idle/connect timeout + extra DB URL params

Operators have reported large numbers of idle Prisma connections that
never get closed. The proxy already forwards `connection_limit` and
`pool_timeout` to the DATABASE_URL, but had no knob for capping idle
or slow connections. Add three new `general_settings` keys that thread
through to the DATABASE_URL / DIRECT_URL query string:

- `database_connect_timeout`  -> Prisma `connect_timeout`
- `database_socket_timeout`   -> Prisma `socket_timeout` (the main
  knob for closing idle connections from the LiteLLM side)
- `database_extra_connection_params` -> untyped passthrough dict for
  any other Prisma URL param (`pgbouncer`, `statement_cache_size`,
  `sslmode`, ...); keys here override LiteLLM defaults.

Refactors the duplicated DATABASE_URL/DIRECT_URL param dicts into a
single `_build_db_connection_url_params` helper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update litellm/proxy/proxy_cli.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: Yassin Kortam <yassinkortam@g.ucla.edu>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
(cherry picked from commit 2f9ac77)
…r genuine auth failures (#29986)

(cherry picked from commit da9d64b)
…thropic streaming logging

Targeted subset of staging commit cfcdf87 (#30202): only the
anthropic_passthrough_logging_handler.py hardening hunks and their four
tests are taken; the rest of that staging batch is intentionally excluded.

(cherry picked from commit cfcdf87)
Three test-only adaptations required by the picks, none touching
production code: restore the AsyncMock import that the upstream
test_proxy_cli.py carries; drop three patch() entries targeting
seed_request_identity, a helper that does not exist on this line; and
re-graft the #30160 test block verbatim from the upstream hunk so the
@patch decorators are included
The picked #29986 builder tests rely on 'from fastapi import status' and
patch seed_request_identity, both present upstream but not on this line;
add the import and drop the patch entries (the helper does not exist
here so there is nothing to neutralize)
@yuneng-berri
yuneng-berri requested a review from a team June 13, 2026 00:55
@CLAassistant

CLAassistant commented Jun 13, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
3 out of 5 committers have signed the CLA.

✅ harish-berri
✅ Sameerlite
✅ yuneng-berri
❌ ishaan-berri
❌ yassin-berriai
You have signed the CLA already but the status is still pending? Let us recheck it.

@yuneng-berri

Copy link
Copy Markdown
Collaborator Author

@greptileai

…combined view (#30327)

The grace-period branch assigned the recursive get_data result (a
finished LiteLLM_VerificationTokenView) back into the variable that the
combined-view dict normalization then subscripts, raising TypeError on
every request made with a rotated key inside its grace window; auth
surfaced that as a 401. Return the recursive result directly instead.

Regression test drives the full get_data flow: old hash misses the view,
deprecated table resolves to the active token, and the call must return
the view object

(cherry picked from commit 5047eaf)
@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Nine cherry-picks from staging onto stable/1.84.x, cutting 1.84.8. The changes address Anthropic streaming reasoning-token counting, grace-period key rotation cache tuple bug, native Azure container routing, Prisma cached-plan recovery via reconnect, DB connection URL configuration knobs, 503 surfacing for DB infrastructure failures during auth, and Anthropic passthrough cost resolution for unknown-model paths.

  • Auth/DB reliability: _lookup_deprecated_key now writes and reads a 3-tuple (was a 2-tuple causing ValueError on every cached cache hit); _query_first_with_cached_plan_fallback reconnects the Prisma client instead of injecting a comment into the query; infrastructure DB failures during auth now surface as 503 instead of 401.
  • Streaming & costing: Reasoning chunks are accumulated across streaming events so final usage correctly splits reasoning vs text tokens; passthrough handlers fall back through litellm_params and SSE chunk content to resolve the costing model when the logging object reports "unknown".
  • Container routing (Azure): api_base endpoint-path stripping and api-version extraction ensure the containers URL is built from the resource root; empty query_params dicts are converted to None so httpx does not silently strip the existing query string.

Confidence Score: 4/5

The backport is safe to merge; the most sensitive paths (auth error classification, cached-plan recovery, grace-period key lookup) are all covered by dedicated mock tests and the logic checks out.

The set of changes is well-scoped and each fix is independently testable. The only nit is a cosmetic double .strip() call in the router. All auth-path changes behave correctly under the exception-type hierarchy, and the new Prisma reconnect path is gated by the existing singleflight attempt_db_reconnect to prevent concurrent client teardowns.

No files require special attention beyond the minor style note in litellm/router.py.

Important Files Changed

Filename Overview
litellm/proxy/utils.py Fixes the 2-tuple/3-tuple cache bug in _lookup_deprecated_key (revoke_at now stored and checked), removes duplicate cache read, and replaces the unsafe DEALLOCATE-then-retry cached-plan recovery with a clean reconnect-then-retry approach.
litellm/proxy/auth/auth_exception_handler.py Adds a 503 path for infrastructure-level DB failures during auth so valid keys are never rejected as 401 during a DB outage; control flow is correct.
litellm/proxy/db/exception_handler.py Adds is_database_service_unavailable_error and is_prisma_engine_internal_error to classify DB infrastructure failures as 503-worthy rather than 401 auth failures.
litellm/proxy/proxy_cli.py Introduces _build_db_connection_url_params; adds four new DB URL config knobs with backward-compatible fallback.
litellm/router.py Falls back to proxy-forwarded model_id for native upstream container IDs; minor double .strip() call.
litellm/proxy/container_endpoints/ownership.py Adds _CONTAINER_STORED_ID_CACHE and _get_stored_container_id for model_id recovery without extra cold-path DB hits.
litellm/llms/anthropic/chat/handler.py Accumulates streamed thinking blocks so _handle_usage can correctly split reasoning vs text tokens.
litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py Adds model fallback resolution and SSE pipeline hardening ([DONE] sentinels, non-JSON frames).
litellm/llms/azure/containers/transformation.py Adds _normalize_api_base and _extract_api_version helpers for correct containers URL construction.
litellm/llms/custom_httpx/container_handler.py Converts empty query_params dict to None to prevent httpx stripping the existing query string.

Reviews (1): Last reviewed commit: "test: align adapted auth builder tests w..." | Re-trigger Greptile

Comment thread litellm/router.py
Comment on lines +5566 to +5570
model_id = decoded.get("model_id") or (
_forwarded_model_id.strip()
if isinstance(_forwarded_model_id, str) and _forwarded_model_id.strip()
else None
)

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.

P2 .strip() is called twice on _forwarded_model_id — once in the guard condition and again in the value expression. Assigning the stripped value to a local variable eliminates the redundant call.

Suggested change
model_id = decoded.get("model_id") or (
_forwarded_model_id.strip()
if isinstance(_forwarded_model_id, str) and _forwarded_model_id.strip()
else None
)
_stripped_model_id = (
_forwarded_model_id.strip()
if isinstance(_forwarded_model_id, str)
else ""
)
model_id = decoded.get("model_id") or (_stripped_model_id or None)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Nine cherry-picks from staging onto stable/1.84.x cutting 1.84.8, accompanied by two test-only adaptation commits, a version bump, and a uv.lock refresh. Every production file is patch-id identical to its staging counterpart with the documented exceptions (dropped build artifacts, grafted test fixtures, and two context-drift resolutions in proxy_cli.py).

  • Auth/DB correctness (core fixes): Fixes the grace-period key rotation bug (2-tuple→3-tuple cache mismatch causing 401 on every request after the first rotation lookup); returns 503 on DB-infra failures during auth instead of 401; adds the Prisma-engine AttributeError edge case to the infra-error classifier; recovers from PostgreSQL "cached plan" errors by reconnecting rather than injecting a unique SQL comment.
  • Anthropic streaming & passthrough: Accumulates streaming thinking blocks so reasoning tokens are correctly split from text tokens at stream end; caps estimated_reasoning_tokens at actual completion_tokens; resolves the costing model for passthrough calls when the body model is \"unknown\"; hardens the SSE pipeline against [DONE] sentinels and non-JSON frames.
  • Azure native container routing: Strips endpoint-specific path suffixes from api_base, prefers the API version embedded in the responses URL, and passes params=None (not {}) to httpx so existing ?api-version=… query strings are not silently stripped.

Confidence Score: 4/5

Safe to merge; all production changes are correct adaptations of staging fixes with comprehensive test coverage and zero new failures on this line's test suite.

The auth DB-infra error classification relies on traceback frame inspection to catch a specific prisma-client-py AttributeError, which is a narrow detection mechanism that would silently regress if the upstream library renames its engine subpackage. Additionally, _get_stored_container_id introduces a direct Prisma table query in the container request path rather than going through a helper function, widening the surface of direct-query call sites. Both are quality/maintainability concerns rather than immediate correctness failures; all other changes are straightforward and well-tested.

litellm/proxy/db/exception_handler.py (traceback-based prisma engine detection) and litellm/proxy/container_endpoints/ownership.py (direct DB query in request path).

Important Files Changed

Filename Overview
litellm/proxy/utils.py Grace-period key rotation: removes duplicate cache read, fixes 2-tuple→3-tuple cache mismatch that caused ValueError on second auth with a rotated key, drops the select clause so revoke_at is populated.
litellm/proxy/db/exception_handler.py Adds is_database_service_unavailable_error and is_prisma_engine_internal_error; the traceback-walk approach in is_prisma_engine_internal_error is brittle to prisma module renames but solves a real edge case with good test coverage.
litellm/proxy/auth/auth_exception_handler.py Adds 503 response for DB-infra failures during auth (instead of 401), correctly placed after the ProxyException re-raise so only raw non-Proxy exceptions reach the new branch.
litellm/llms/anthropic/chat/handler.py Accumulates streaming thinking-block deltas in reasoning_content_chunks so _handle_usage can split reasoning vs text tokens correctly at stream end.
litellm/llms/anthropic/chat/transformation.py Caps estimated_reasoning_tokens at actual completion_tokens with min(), preventing text_tokens from going negative when the token-counter estimate overshoots.
litellm/proxy/proxy_cli.py Refactors DB URL param construction into _build_db_connection_url_params; adds connect_timeout, socket_timeout, pgbouncer, and extra_params knobs; backward compatible (all new fields are opt-in).
litellm/proxy/pass_through_endpoints/llm_provider_handlers/anthropic_passthrough_logging_handler.py Adds _resolve_costing_model to fall back to deployment/model_group when model is 'unknown', adds _extract_model_from_anthropic_chunks to recover model from SSE stream, and hardens the SSE pipeline against [DONE] sentinels and non-JSON frames.
litellm/proxy/container_endpoints/ownership.py Adds _CONTAINER_STORED_ID_CACHE to recover model_id from the encoded ID stored at create time for native upstream container IDs; get_container_forwarding_params becomes async to support the DB lookup; makes a direct Prisma query bypassing helper functions.
litellm/router.py Falls back to the proxy-forwarded model_id when a container_id carries no LiteLLM routing payload (native Azure hex IDs), so deployment credentials are applied correctly.
litellm/proxy/_types.py Adds four new optional ConfigGeneralSettings fields: database_connect_timeout, database_socket_timeout, database_extra_connection_params, database_disable_prepared_statements — all None-defaulted, backward compatible.

Reviews (2): Last reviewed commit: "test: align adapted auth builder tests w..." | Re-trigger Greptile

Comment on lines +113 to +145
def is_prisma_engine_internal_error(e: Exception) -> bool:
"""True iff ``e`` is a non-``PrismaError`` exception raised from inside
prisma-client-py's query-engine layer.

During the instant a DB connection is torn down, the query engine can
return a malformed error payload (``user_facing_error.meta`` is
``null``). prisma-client-py's ``handle_response_errors`` then crashes
with ``AttributeError: 'NoneType' object has no attribute 'get'``
before it can raise the proper P1001 "can't reach database server"
error. That AttributeError carries no connection keyword, so it can't
be matched by message; identify it by its ``prisma.engine`` origin
instead.

Recognized ``PrismaError`` subclasses are excluded: connectivity ones
are already classified by type/keyword above, and data-layer ones
(the DB IS reachable) must stay 401.
"""
import prisma

if isinstance(e, prisma.errors.PrismaError):
return False
tb = getattr(e, "__traceback__", None)
while tb is not None:
if tb.tb_frame.f_globals.get("__name__", "").startswith("prisma.engine"):
return True
tb = tb.tb_next
return False

@staticmethod
def is_database_service_unavailable_error(e: Exception) -> bool:
"""True iff the exception means the database could not answer at the
infrastructure level (connection refused, socket/interface failure,
timeout) rather than a genuine auth failure (key not found) or a

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.

P2 Traceback inspection is brittle to prisma module renames

is_prisma_engine_internal_error classifies an AttributeError as a DB-infra failure by walking e.__traceback__ and checking whether any frame's __name__ starts with "prisma.engine". This works today, but if prisma-client-py ever renames its engine subpackage (e.g. to prisma._engine, prisma_client.engine, or anything that doesn't share this prefix) the check silently returns False, and the same AttributeError that caused the auth-outage regression would start returning 401 again.

Consider recording a recognizable sentinel on the exception at the raise site inside the prisma shim, or pinning a prisma version range in pyproject.toml alongside a comment that this detection depends on the current naming convention.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines 241 to 286
return owner


async def _get_stored_container_id(
original_container_id: str, custom_llm_provider: str
) -> Optional[str]:
"""Return the ``unified_object_id`` stored at create time, if any.

Used by :func:`get_container_forwarding_params` to recover the
deployment ``model_id`` for native upstream container IDs: the stored
value is the encoded form produced by ``encode_container_id_in_response``
when the router selected a specific deployment.
"""
model_object_id = _container_model_object_id(
original_container_id, custom_llm_provider
)

cached = _CONTAINER_STORED_ID_CACHE.get_cache(model_object_id)
if cached == _NEGATIVE_STORED_ID_SENTINEL:
return None
if isinstance(cached, str) and cached:
return cached

prisma_client = await _get_prisma_client()
if prisma_client is None:
return None

row = await prisma_client.db.litellm_managedobjecttable.find_first(
where={
"model_object_id": model_object_id,
"file_purpose": CONTAINER_OBJECT_PURPOSE,
}
)
stored_id = getattr(row, "unified_object_id", None) if row is not None else None
_CONTAINER_STORED_ID_CACHE.set_cache(
model_object_id,
(
stored_id
if isinstance(stored_id, str) and stored_id
else _NEGATIVE_STORED_ID_SENTINEL
),
)
return stored_id if isinstance(stored_id, str) and stored_id else None


async def assert_user_can_access_container(

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.

P2 Direct Prisma query in request path bypasses helper functions

_get_stored_container_id issues a litellm_managedobjecttable.find_first query directly against prisma_client.db, mirroring the existing pattern in _get_container_owner. The codebase rule requires all DB queries in the request path to go through the get_team/get_user/get_key object helper functions. The container path isn't the auth hot-path, and the call is cache-guarded, so the practical impact is low — but it widens the set of direct-query call sites that need to be updated if the DB access pattern changes (e.g., read-replica splitting, query logging).

Rule Used: What: In critical path of request, there should be... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@yuneng-berri yuneng-berri changed the title chore(release): backport #27319, #27756, #27921, #28395, #29983, #29984, #29986, #30160 to stable/1.84.x and cut 1.84.8 chore(release): backport #27319, #27756, #27921, #28395, #29983, #29984, #29986, #30160, #30327 to stable/1.84.x and cut 1.84.8 Jun 13, 2026

@mateo-berri mateo-berri 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.

LGTM; thanks!

@mateo-berri
mateo-berri merged commit 34e9d7d into stable/1.84.x Jun 13, 2026
46 of 62 checks passed
@mateo-berri
mateo-berri deleted the litellm_backport_1_84_x_0612 branch June 13, 2026 01:21
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.

7 participants