Skip to content

fix: backport eight backport-stable fixes to rc/1.102.0 (#40596, #41046, #41086, #41171, #41178, #41283, #41495, #41689) - #41854

Merged
mateo-berri merged 8 commits into
rc/1.102.0from
litellm_backport_stable_batch_rc_1_102_0
Sep 18, 2026
Merged

mateo-berri merged 8 commits into
rc/1.102.0from
litellm_backport_stable_batch_rc_1_102_0

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • v1.102.0 stable is expected Sat, Sep 19 and eight backport-stable fixes only landed on main
  • rc/1.102.0 (4fd5bc6, v1.102.0-rc.2) still ships every one of those regressions
  • The worst one: litellm[cli] cannot even import on Python 3.10

How it solves it:

  • Cherry-picks each PR's merge commit onto rc/1.102.0, one commit per PR, provenance in the body
  • Three conflicts resolved to match what merged on main: two in test files, one a hunk for a file this line does not have (details below)
  • No version bump: the rc number lives only in the tag

User Flow

The flow below is the one fix reproduced by hand on this line (Python 3.10 CLI). The other seven keep the User Flow written in their original PR, at code identical to what this branch carries: #41086, #41178, #41283, #41171, #40596, #41495, #41689

Before: a developer on Python 3.10 installs the CLI from the rc and cannot run a single lite command

  1. They run pip install 'litellm[cli]==1.102.0rc2' on Python 3.10 and the install succeeds
  2. They run lite --version and get a traceback ending in ImportError: cannot import name 'StrEnum' from 'enum', exit code 1
  3. lite login, lite keys list, and lite models list all die with the same traceback before any argument is read, so the CLI never reaches GET http://localhost:4000/health/readiness or any other proxy route

After: the same developer runs every lite command on Python 3.10

  1. They run pip install 'litellm[cli]==1.102.0' on Python 3.10 and the install succeeds
  2. They run lite --version and see LiteLLM Proxy CLI Version: 1.102.0, the configured server URL, and the server version from GET http://localhost:4000/health/readiness (or (unavailable) when no proxy is running), exit code 0
  3. lite login, lite keys list, and lite models list reach the proxy routes they always did

Backported PRs

In pick order (each row is one commit on this branch, cherry-picked from the PR's merge commit on main):

PR Fix Regressed in Commit here Pick
#41086 org admins' own teams in other orgs hidden on team list v1.83.10 31d78fa conflict, see notes
#41046 CLI import crash on Python 3.10 v1.102.0-rc.1 034998b clean
#41178 per-request routing_strategy override routes blind v1.102.0-dev.1 7c1186e clean
#41283 access-group raw SQL writes sent to the read replica v1.100.0 24e583c clean
#41171 spend not tracked for streams a deployment hook converted v1.100.0 e6f29fb clean
#40596 rate-limit fallbacks return 500 with OpenTelemetry on v1.93.0.dev1 8f8b47d clean
#41495 post-call deployment hook skipped on converted chat streams with #41171 707a81a conflict, see notes
#41689 bridged /v1/responses follow-up turns return 400 v1.102.0-rc.1 3a7a204 conflict, see notes

Conflict notes, each resolved to the merged upstream behavior with nothing new:

Still open on main with the label and not in this batch: #41235 and #41347. stable/1.101.x is untouched

Relevant issues

Affected release

Every fix here is a regression fix already labeled backport-stable on main. The oldest regressed in v1.83.10 (#41086), the newest in v1.102.0-rc.1 (#41046, #41689); all eight are present in v1.102.0-rc.2, the current tip of rc/1.102.0

Linear ticket

Resolves LIT-8123

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests (the 32 regression tests the eight PRs carry come along, listed under Proof of Fix)
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.): no required checks on this line; 39 of 42 CircleCI jobs plus the Buildkite e2e stage are green at the tip, proxy_multi_instance_tests went green on a rerun after its first run timed out cloning from github.com before any test ran, and the three red jobs are the pre-existing Together AI rot described under Caveats
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Shared setup for the CLI case: a Python 3.10.20 venv holding litellm's base and cli dependencies straight from uv.lock (uv export --frozen --no-emit-project --no-dev --no-hashes --extra cli, then uv pip install -r), with the litellm package loaded from a source tree through PYTHONPATH rather than pip-installed, which is why the CLI's own version line reads unknown. The lite console script is litellm.proxy.client.cli:cli, so python3.10 -c "from litellm.proxy.client.cli import cli; cli()" --version is the same entrypoint lite --version runs. Before is the litellm/ tree at rc/1.102.0 4fd5bc6 (git archive), After is this branch

Shared setup for the regression-test case: this branch's 13 touched test files (which carry the 32 tests the eight PRs add) run in the worktree's venv (Python 3.14.3). After runs them from the worktree; Before runs the same 13 files copied into a detached checkout of the rc tip 4fd5bc6, with litellm verified to import from that checkout, since python -m pytest puts the working directory first on sys.path and a Before run started from the branch worktree would test the branch

Before (4fd5bc6)

lite --version on Python 3.10

  1. PYTHONPATH=<rc/1.102.0 tip 4fd5bc6b22 litellm tree> python3.10 -c "from litellm.proxy.client.cli import cli; cli()" --version
  2. Output:
    from .pi import (
  File ".../before_tree/litellm/proxy/client/cli/commands/pi.py", line 13, in <module>
    from enum import StrEnum
ImportError: cannot import name 'StrEnum' from 'enum' (.../cpython-3.10-macos-aarch64-none/lib/python3.10/enum.py)
exit 1

The eight PRs' regression tests on the rc tip

  1. <worktree venv>/python -m pytest -q --continue-on-collection-errors <the 13 touched test files> from the detached rc-tip checkout
  2. Output:
10 files (every touched test file except tests/test_litellm/test_utils.py):  19 failed, 1143 passed, 1 error
  ERROR tests/test_litellm/responses/litellm_completion_transformation/test_handler.py
    ImportError: cannot import name 'ADDRESSED_RESPONSE_ID_FIELD' from 'litellm.types.utils'
  FAILED tests/test_litellm/litellm_core_utils/test_litellm_logging.py::test_add_dynamic_callback_registers_once_per_list_without_touching_the_callers_list
  FAILED tests/test_litellm/router_strategy/test_router_routing_groups.py::test_bind_override_selector_to_request_binds_once_and_ignores_requests_without_logging
  FAILED tests/test_litellm/proxy/management_helpers/test_access_group_model_sync.py::test_delete_counts_backing_rows_on_the_writer_not_a_lagging_replica_while_writer_flagged_unavailable
  FAILED tests/test_litellm/proxy/test_common_request_processing.py::TestPreCallWithFallbacksOnLocalRateLimit::test_fallback_lookup_uses_alias_resolved_model_group
  FAILED tests/test_litellm/router_strategy/test_router_routing_groups.py::test_latency_based_override_learns_from_the_overriding_requests
  FAILED tests/test_litellm/router_strategy/test_router_routing_groups.py::test_least_busy_override_releases_the_slot_when_the_overriding_request_fails
  FAILED tests/test_litellm/router_strategy/test_router_routing_groups.py::test_least_busy_override_sees_the_overriding_request_in_flight
  FAILED tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py::test_list_team_v1_org_admin_own_query_keeps_memberships_in_other_orgs
  FAILED tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py::test_list_team_v2_org_admin_own_query_keeps_memberships_in_other_orgs
  FAILED tests/test_litellm/proxy/management_endpoints/test_team_endpoints.py::test_list_team_v2_org_admin_own_user_id_sees_all_org_teams
  FAILED tests/test_litellm/proxy/management_helpers/test_access_group_key_sync.py::test_membership_attach_and_detach_updates_stay_on_the_writer_while_writer_flagged_unavailable
  FAILED tests/test_litellm/router_strategy/test_router_routing_groups.py::test_override_matching_a_routing_group_strategy_records_each_request_once
  FAILED tests/test_litellm/router_strategy/test_router_routing_groups.py::test_override_selector_is_bound_only_to_the_request_that_asked_for_it
  FAILED tests/test_litellm/proxy/management_helpers/test_access_group_key_sync.py::test_regeneration_repoint_update_stays_on_the_writer_while_writer_flagged_unavailable
  FAILED tests/test_litellm/proxy/management_helpers/test_access_group_model_sync.py::test_rename_update_stays_on_the_writer_while_writer_flagged_unavailable
  FAILED tests/test_litellm/router_strategy/test_router_routing_groups.py::test_sync_least_busy_override_sees_the_overriding_request_in_flight
  FAILED tests/test_litellm/proxy/test_common_request_processing.py::TestPreCallWithFallbacksOnLocalRateLimit::test_v3_limiter_with_otel_span_falls_back_from_client_request
  FAILED tests/test_litellm/proxy/test_common_request_processing.py::TestPreCallWithFallbacksOnLocalRateLimit::test_v3_limiter_with_otel_span_returns_429_when_fallbacks_exhausted
  FAILED tests/test_litellm/proxy/db/test_routing_prisma_wrapper.py::test_writer_wrapper_keeps_raw_sql_on_the_writer_while_writer_flagged_down
tests/test_litellm/test_utils.py:                                            1 error
  ImportError: cannot import name 'ADDRESSED_RESPONSE_ID_FIELD' from 'litellm.types.utils'
tests/local_testing/test_caching_handler.py:                                 1 failed, 27 passed
  FAILED tests/local_testing/test_caching_handler.py::test_should_defer_streaming_cache_hit_callbacks_for_any_streaming_request
tests/test_litellm/proxy/client/cli/test_pi.py (isolated HOME):              33 passed
  1. Read: of the 32 tests the eight PRs add, 18 fail on the rc tip, 9 cannot be collected there (the 8 in test_utils.py and the 1 in test_handler.py import ADDRESSED_RESPONSE_ID_FIELD, which fix(responses): keep the addressed response id off bridged provider requests #41689 introduces), and 5 already pass there: fix(cli): drop enum.StrEnum so the CLI imports on Python 3.10 #41046's test_listing_failure_is_str_enum (Python 3.14 has StrEnum, which is why the CLI case above runs on Python 3.10), fix(router): bind per-request routing_strategy override selectors to the request's callbacks #41178's test_override_matching_the_router_strategy_is_not_bound_twice, fix(proxy): retry rate-limit fallbacks from a pristine request snapshot #40596's test_key_metadata_disable_fallbacks_returns_429_instead_of_retrying, and fix(logging): track spend for streams a deployment hook converted to non-streaming #41171's two cache-hit tests in tests/test_litellm/caching/test_caching_handler.py. Two existing tests the picks change also fail on the rc tip: test_list_team_v2_org_admin_own_user_id_sees_all_org_teams (fix(proxy): keep org admins' own team memberships in other orgs visible on team list #41086) and test_should_defer_streaming_cache_hit_callbacks_for_any_streaming_request (fix(logging): track spend for streams a deployment hook converted to non-streaming #41171)

After (3a7a204)

lite --version on Python 3.10

  1. PYTHONPATH=<this branch> python3.10 -c "from litellm.proxy.client.cli import cli; cli()" --version
  2. Output:
LiteLLM Proxy CLI Version: unknown
LiteLLM Proxy Server URL: http://localhost:4000
LiteLLM Proxy Server Version: (unavailable)
exit 0

The eight PRs' regression tests on this branch

  1. .venv/bin/python -m pytest -q <the 13 touched test files> from the worktree root
  2. Output:
10 files (every touched test file except tests/test_litellm/test_utils.py):  1165 passed
tests/test_litellm/test_utils.py:                                            379 passed
tests/local_testing/test_caching_handler.py:                                 28 passed
tests/test_litellm/proxy/client/cli/test_pi.py (isolated HOME):              33 passed
  1. BASE_REF=origin/rc/1.102.0 make check: Python lint, the ruff-strict, type-discipline, test-quality, and basedpyright budget gates (all measured against origin/rc/1.102.0), the circular-import check, and ruff format --check all pass. The lazy OpenAPI snapshot regenerated with zero diff under Python 3.12, the version CI uses

Type

🐛 Bug Fix

Caveats (if any)

Low

  • Seven of the eight fixes have no fresh live before/after run on this line; on this PR they are verified by their regression tests (fail on the rc tip, pass here, shown above) and by the CircleCI suites at the tip
    • Each original PR's Proof of Fix section holds the live run, captured on main at code identical to what this branch carries (five clean picks, three whose only conflicts were in test files or a file this line lacks), and the dependency walk found no caller on this line of any symbol the picks re-sign or move that main does not also have
    • Left as is because re-running seven live rigs (read replica, OpenTelemetry, org and team fixtures, deployment hooks, bridged /v1/responses turns) at two commits each does not fit before the v1.102.0 tag expected Sat, Sep 19, and missing that tag ships all eight regressions in stable, the exact harm this batch exists to prevent
  • The After leg of the CLI case ran with no proxy up, so its server-version line reads (unavailable); the fix is import-time and the readiness round trip that follows is the same code at both commits
  • fix(cli): drop enum.StrEnum so the CLI imports on Python 3.10 #41046's pick carries its .github/workflows/test-code-quality.yml hunk (a lite version smoke step on Python 3.10) so the commit stays the merge commit verbatim; that workflow does not run on PRs into this line
  • The worktree venv make check ran under Python 3.14 flagged the lazy OpenAPI snapshot as stale; the only diff was Python 3.13+ docstring dedent, and a Python 3.12 regeneration matches the committed file byte for byte, so the regenerated file was discarded
  • fix(responses): honor caller stream flag when provider forces SSE (internal copy of #34095) #41235 and fix(team): apply team_member_budget updates to members still on the team default #41347 still carry backport-stable and are open on main; they are not in this batch and need their own pick once merged
  • CircleCI local_testing_part1, local_testing_part2, and llm_translation_testing are red at the tip only on Together AI tests hard-coded to openai/gpt-oss-20b, which Together no longer serves serverless; fix(license): backport the wildcard license auto_router grant to rc/1.102.0 (#41684) #41701, the last PR merged into this line, failed the same tests, and main is green because it rewrote those tests after the rc cut (1aa2e19 and follow-ups, test-only). Not a pick of this batch, which carries no test change outside the eight PRs

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

  • 3a7a204 passes /live-pr-risk

…le on team list

Backport of #41086 to rc/1.102.0.
Cherry-picked from merge commit 4123b4b (main), originally by app/devin-ai-integration.

rc/1.102.0 has no litellm/proxy/auth/resolvers/grants.py, so its one-line import change is dropped; auth_checks.py imports UserNotFoundError from the new types module, so every importer on this line still resolves.
Backport of #41046 to rc/1.102.0.
Cherry-picked from merge commit 1ba9766 (main), originally by app/devin-ai-integration.
…the request's callbacks

Backport of #41178 to rc/1.102.0.
Cherry-picked from merge commit 1ca4579 (main), originally by app/devin-ai-integration.
…er_unavailable is stale

Backport of #41283 to rc/1.102.0.
Cherry-picked from merge commit 0e5be27 (main), originally by app/devin-ai-integration.
…non-streaming

Backport of #41171 to rc/1.102.0.
Cherry-picked from merge commit c3222ec (main), originally by app/devin-ai-integration.
Backport of #40596 to rc/1.102.0.
Cherry-picked from merge commit c5325b1 (main), originally by app/devin-ai-integration.
Backport of #41495 to rc/1.102.0.
Cherry-picked from merge commit 0add8c0 (main), originally by app/devin-ai-integration.

The only conflict was the test import header: the rc line never gained the logging_executor import that main carries next to this change, so only the MockResponseIterator import comes along.
…equests

Backport of #41689 to rc/1.102.0.
Cherry-picked from merge commit 07b5051 (main), originally by app/devin-ai-integration.

Both conflicts were in test files: the rc line lacks the Codex additional_tools tests that sit next to the new test in test_handler.py on main, and its test_utils.py imports all_litellm_params on a separate line, so only this PR's own additions (the imports, the recording handler, and the two new tests) are taken.
@greptile-apps

greptile-apps Bot commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

The backported fixes appear sound, but the explicit repository requirement prohibiting new per-request database lookups must be satisfied before merging.

Findings

  1. P2 Extra Database Request ▶

Summary

Backports eight regression fixes to the 1.102.0 release candidate.

  • Restores Python 3.10 compatibility for the lite CLI.
  • Corrects team-list authorization, request-specific routing, writer routing, fallback handling, stream callbacks, cache replay, and Responses API follow-up behavior.
  • Adds regression coverage and a Python 3.10 CLI workflow check.

Reviews (2) · Last reviewed commit: "fix(responses): keep the addressed respo..."

Comment on lines +4818 to +4837
async def _get_user_team_ids_from_db(
user_id: str,
prisma_client: PrismaClient,
user_api_key_cache: UserApiKeyCache,
proxy_logging_obj: ProxyLogging,
) -> tuple[str, ...]:
try:
user: Final = await get_user_object(
user_id=user_id,
prisma_client=prisma_client,
user_api_key_cache=user_api_key_cache,
user_id_upsert=False,
proxy_logging_obj=proxy_logging_obj,
check_db_only=True,
)
except UserNotFoundError:
return ()
return tuple(user.teams or ()) if user is not None else ()


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 Extra Database Request

The new org-admin self-query path calls get_user_object(..., check_db_only=True), adding a cache-bypassing database lookup before the paginated team query. This violates the repository directive to avoid creating new database requests in request paths. Reuse membership data already loaded for authorization or combine this lookup with the existing query. This repository requirement must be satisfied before merging.

Rule Used: What: Avoid creating new database requests or Router objects in the critical request path. Why: Creating these objects on every request causes performance degradation and unnecessary resource consumption. (source)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cherry-pick of #41086 as merged on main. The lookup runs only when an org admin lists their own teams, a management route, not LLM traffic.

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.

That’s a fair distinction. The added lookup is confined to the management-only list_team_v2 path, runs only for an org admin’s own-team query, and uses the existing get_user_object helper. It is not on the LLM request path covered by the critical-path database-query concern, so I’m withdrawing this finding; no change is required here.

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 3a7a204. Configure here.

@mateo-berri
mateo-berri merged commit 1a993c3 into rc/1.102.0 Sep 18, 2026
56 of 59 checks passed
@mateo-berri
mateo-berri deleted the litellm_backport_stable_batch_rc_1_102_0 branch September 18, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant