Skip to content

fix(proxy): stop labelling management and health rejections as auth failures - #39558

Open
mateo-berri wants to merge 1 commit into
litellm_openai_error_payload_spend_managementfrom
litellm_management_route_error_types
Open

fix(proxy): stop labelling management and health rejections as auth failures#39558
mateo-berri wants to merge 1 commit into
litellm_openai_error_payload_spend_managementfrom
litellm_management_route_error_types

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Management routes label every rejection type: auth_error
  • /team/info says auth_error for a team that does not exist
  • /user/update says auth_error for a bad budget_duration
  • auth_error is not an OpenAI error type at all
  • Clients branching on type retry the key, not the field

How it solves it:

  • Blanket handlers read the type off the exception
  • Every status each branch answered with is kept
  • Deliberate ProxyExceptions pass through with their own type
  • Genuine auth and SSO sites keep auth_error, untouched

User Flow

Before: a platform admin scripting the management API with a valid admin key gets every rejection labelled an auth failure, so the client re-authenticates in a loop instead of fixing the request

  1. They call GET https://litellm-domain/team/info?team_id=no-such-team-6842 with Authorization: Bearer <admin key>
  2. It comes back 404 with {"error":{"message":"Team not found, passed team id: no-such-team-6842.","type":"auth_error","param":null,"code":"404"}}
  3. Their client branches on error.type, reads auth_error, refreshes the admin key, and retries the same bad team id, looping until it gives up
  4. They call POST https://litellm-domain/user/update with {"user_id":"u6842repro","budget_duration":"not-a-duration"} and get 400 with "type":"auth_error" and a message prefixed Authentication Error,
  5. The same happens on POST /key/update, POST /organization/member_add, POST /model/new, POST /model/update, POST /model/delete, GET /health/services, POST /queue/chat/completions and POST /config/update
  6. They send a genuinely bad key to GET https://litellm-domain/team/info and get 401 with an auth-flavoured type as well, so nothing in the response body tells them which of the two problems they actually have

After: the same calls come back with the type that matches what went wrong, so the client fixes the field and only retries credentials when the credentials are the problem

  1. They call GET https://litellm-domain/team/info?team_id=no-such-team-6842 with Authorization: Bearer <admin key>
  2. It comes back 404 with {"error":{"message":"Team not found, passed team id: no-such-team-6842.","type":"invalid_request_error","param":null,"code":"404"}}, and the message no longer carries the Authentication Error, prefix
  3. Their client reads invalid_request_error, stops retrying the key, and surfaces the bad team id to the operator
  4. They call POST https://litellm-domain/user/update with the same bad budget_duration and get 400 with "type":"invalid_request_error"
  5. The other routes answer the same way, each keeping the status it already returned: a 404 or 400 or 422 now says invalid_request_error, a 500 says internal_server_error, a 403 says permission_error
  6. They send a genuinely bad key to GET https://litellm-domain/team/info and still get 401 with "type":"token_not_found_in_db", and POST https://litellm-domain/login with a wrong password still answers 401 with "type":"auth_error", so a real credential failure is now distinguishable from a bad team id

Scope

92 sites across 14 files pin ProxyErrorTypes.auth_error. This PR changes 22 of them, in the 11 blanket except Exception blocks that guard a management or health route, and deliberately leaves the other 70.

Changed, one line each, all now going through a shared proxy_exception_for helper:

Route Handler default Status seen Type before Type after
POST /user/update 400 400 auth_error invalid_request_error
POST /key/update 400 400 auth_error invalid_request_error
GET /team/info 400 404 auth_error invalid_request_error
POST /organization/member_add 500 404 auth_error invalid_request_error
POST /model/delete 400 400 auth_error invalid_request_error
POST /model/update 400 400 auth_error invalid_request_error
POST /model/new 400 500 auth_error internal_server_error
GET /health/services 500 400 auth_error invalid_request_error
POST /queue/chat/completions 400 400 auth_error invalid_request_error
POST /config/update 400 400 auth_error invalid_request_error
GET /get/config/callbacks 400 400 auth_error invalid_request_error

Left alone on purpose:

Left alone Sites Reason
litellm/proxy/auth/ 21 real credential and JWT failures
management_endpoints/ui_sso.py 36 real SSO login failures
proxy_server.py login and onboarding 9 real login failures
model_management_endpoints.py 403 checks 3 real authorization denials
utils.py handle_exception_on_proxy 1 PR #39555 owns that handler

The last row is why the diff stops where it does: the shared handler is being fixed separately, so touching it here would collide.

list_keys and key_aliases in key_management_endpoints.py are the near miss. Both wrap their body in the same blanket except Exception, and both still hardcode message="Authentication Error, " + str(e) while passing the caught exception's own status through, so a 400 there answers internal_server_error with an auth-flavoured message. Neither is one of the 92 auth_error sites, so neither is in this ticket's scope, and folding them in would widen the diff and force the whole QA to run again. They are worth their own follow-up.

Base branch

This branches off litellm_openai_error_payload_spend_management (PR #39542), not off litellm_internal_staging, and can only merge once #39521, #39536, #39540 and #39542 land ahead of it. Two reasons: litellm/proxy/common_utils/openai_error_payload.py, which the fix extends, does not exist on staging yet, and #39540 and #39542 rewrite the param= line directly above every one of the 22 type= lines this PR replaces. Branching off staging would have meant a duplicate copy of that module plus 22 guaranteed conflicts.

Relevant issues

Linear ticket

Resolves LIT-6842

Pre-Submission checklist

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

  • I have added meaningful tests
  • 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.)
  • 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

Two live proxies, same config, same cases, same order, differing only in the commit they booted from.
Each ran two uvicorn workers against its own Postgres database, and every call below uses a valid
admin key.

Boot on either side:

python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml --port <port> --num_workers 2 --use_v2_migration_resolver

Before ran on port 21550, After on port 31620.

Before (f9051a1)

1. Sanity: a real provider call succeeds

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/v1/chat/completions' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model":"anthropic-haiku-4-5","messages":[{"role":"user","content":"say lit6842 and nothing else"}],"max_tokens":16}'
  1. Observed, HTTP 200:
{"id":"chatcmpl-f62b3ddf-1008-442e-9c59-035d62f33319","model":"anthropic-haiku-4-5","object":"chat.completion","choices":[{"finish_reason":"stop","index":0,"message":{"content":"lit6842","role":"assistant"}}],"usage":{"completion_tokens":6,"prompt_tokens":15,"total_tokens":21}}

2. GET /team/info, team that does not exist

  1. Run:
curl -sS -X GET 'http://127.0.0.1:21550/team/info?team_id=no-such-team-6842' -H 'Authorization: Bearer sk-1234'
  1. Observed, HTTP 404:
{"error":{"message":"{'message': 'Team not found, passed team id: no-such-team-6842.'}","type":"auth_error","param":null,"code":"404"}}

3. POST /user/update, unparseable budget_duration

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/user/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"user_id":"u6842repro","budget_duration":"not-a-duration"}'
  1. Observed, HTTP 400:
{"error":{"message":"{'error': \"Invalid budget_duration 'not-a-duration'. Use a format like '1h', '24h', '7d', or '30d'.\"}","type":"auth_error","param":null,"code":"400"}}

4. POST /key/update, unparseable budget_duration

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/key/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"key":"<a key from /key/generate on that leg>","budget_duration":"not-a-duration"}'
  1. Observed, HTTP 400:
{"error":{"message":"{'error': \"Invalid budget_duration 'not-a-duration'. Use a format like '1h', '24h', '7d', or '30d'.\"}","type":"auth_error","param":null,"code":"400"}}

5. POST /organization/member_add, organization that does not exist

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/organization/member_add' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"organization_id":"no-such-org-6842","member":{"role":"internal_user","user_email":"lit6842@example.com"}}'
  1. Observed, HTTP 404:
{"error":{"message":"{'error': 'Organization not found for organization_id=no-such-org-6842'}","type":"auth_error","param":null,"code":"404"}}

6. POST /model/delete, model id that does not exist

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/model/delete' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"id":"no-such-model-6842"}'
  1. Observed, HTTP 400:
{"error":{"message":"{'error': 'Model with id=no-such-model-6842 not found in db'}","type":"auth_error","param":null,"code":"400"}}

7. POST /model/update, model id that does not exist

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/model/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model_name":"lit6842-ghost","litellm_params":{"model":"openai/gpt-4o-mini"},"model_info":{"id":"no-such-model-6842"}}'
  1. Observed, HTTP 400:
{"error":{"message":"Authentication Error, model not found","type":"auth_error","param":null,"code":"400"}}

8. POST /model/new, same model_info.id twice, so the db write fails

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/model/new' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model_name":"lit6842-dup","litellm_params":{"model":"openai/gpt-4o-mini"},"model_info":{"id":"lit6842-fixed-id"}}'
  1. Observed, HTTP 500:
{"error":{"message":"{'error': 'Failed to add model to db. Check your server logs for more details.'}","type":"auth_error","param":null,"code":"500"}}

9. GET /health/services, service name that is not in the list

  1. Run:
curl -sS -X GET 'http://127.0.0.1:21550/health/services?service=not-a-service' -H 'Authorization: Bearer sk-1234'
  1. Observed, HTTP 400:
{"error":{"message":"{'error': \"Service must be in list. Service=not-a-service not in typing.Union[typing.Literal['slack_budget_alerts', 'langfuse', ...], str]\"}","type":"auth_error","param":null,"code":"400"}}

10. POST /queue/chat/completions, no priority

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/queue/chat/completions' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model":"anthropic-haiku-4-5","messages":[{"role":"user","content":"hi"}]}'
  1. Observed, HTTP 400:
{"error":{"message":"Authentication Error, Router.schedule_acompletion() missing 1 required positional argument: 'priority'","type":"auth_error","param":null,"code":"400"}}

11. POST /queue/chat/completions, valid priority, model that does not exist

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/queue/chat/completions' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model":"no-such-model-6842","messages":[{"role":"user","content":"hi"}],"priority":0}'
  1. Observed, HTTP 400:
{"error":{"message":"Authentication Error, litellm.BadRequestError: You passed in model=no-such-model-6842. There are no healthy deployments for this model. Received Model Group=no-such-model-6842\nAvailable Model Group Fallbacks=None","type":"auth_error","param":null,"code":"400"}}

12. POST /config/update, success_callback that is not a list of strings

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/config/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"litellm_settings":{"success_callback":[{"not":"a-string"}]}}'
  1. Observed, HTTP 400:
{"error":{"message":"Authentication Error, unhashable type: 'dict'","type":"auth_error","param":null,"code":"400"}}

13. GET /get/config/callbacks, after a scalar success_callback is stored

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/config/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"litellm_settings":{"success_callback":5}}'
curl -sS -X GET 'http://127.0.0.1:21550/get/config/callbacks' -H 'Authorization: Bearer sk-1234'
  1. Observed, HTTP 400:
{"error":{"message":"Authentication Error, 'int' object is not iterable","type":"auth_error","param":null,"code":"400"}}

14. Auth control: GET /team/info with a key that does not exist

  1. Run:
curl -sS -X GET 'http://127.0.0.1:21550/team/info?team_id=whatever' -H 'Authorization: Bearer sk-not-a-real-key-6842'
  1. Observed, HTTP 401:
{"error":{"message":"Authentication Error, Invalid proxy server token passed. Received API Key = sk-...6842, Key Hash (Token) =249e3414...","type":"token_not_found_in_db","param":"key","code":"401"}}

15. Auth control: POST /login with the wrong password

  1. Run:
curl -sS -X POST 'http://127.0.0.1:21550/login' -d 'username=admin&password=definitely-wrong-6842'
  1. Observed, HTTP 401:
{"error":{"message":"Invalid credentials used to access UI.\nCheck 'UI_USERNAME', 'UI_PASSWORD' in .env file","type":"auth_error","param":"invalid_credentials","code":"401"}}

After (0c38a25)

1. Sanity: a real provider call succeeds

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/v1/chat/completions' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model":"anthropic-haiku-4-5","messages":[{"role":"user","content":"say lit6842 and nothing else"}],"max_tokens":16}'
  1. Observed, HTTP 200:
{"id":"chatcmpl-b9411883-0ab9-4228-a511-597574650218","model":"anthropic-haiku-4-5","object":"chat.completion","choices":[{"finish_reason":"stop","index":0,"message":{"content":"lit6842","role":"assistant"}}],"usage":{"completion_tokens":6,"prompt_tokens":15,"total_tokens":21}}

2. GET /team/info, team that does not exist

  1. Run:
curl -sS -X GET 'http://127.0.0.1:31620/team/info?team_id=no-such-team-6842' -H 'Authorization: Bearer sk-1234'
  1. Observed, HTTP 404:
{"error":{"message":"{'message': 'Team not found, passed team id: no-such-team-6842.'}","type":"invalid_request_error","param":null,"code":"404"}}

3. POST /user/update, unparseable budget_duration

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/user/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"user_id":"u6842repro","budget_duration":"not-a-duration"}'
  1. Observed, HTTP 400:
{"error":{"message":"{'error': \"Invalid budget_duration 'not-a-duration'. Use a format like '1h', '24h', '7d', or '30d'.\"}","type":"invalid_request_error","param":null,"code":"400"}}

4. POST /key/update, unparseable budget_duration

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/key/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"key":"<a key from /key/generate on that leg>","budget_duration":"not-a-duration"}'
  1. Observed, HTTP 400:
{"error":{"message":"{'error': \"Invalid budget_duration 'not-a-duration'. Use a format like '1h', '24h', '7d', or '30d'.\"}","type":"invalid_request_error","param":null,"code":"400"}}

5. POST /organization/member_add, organization that does not exist

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/organization/member_add' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"organization_id":"no-such-org-6842","member":{"role":"internal_user","user_email":"lit6842@example.com"}}'
  1. Observed, HTTP 404:
{"error":{"message":"{'error': 'Organization not found for organization_id=no-such-org-6842'}","type":"invalid_request_error","param":null,"code":"404"}}

6. POST /model/delete, model id that does not exist

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/model/delete' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"id":"no-such-model-6842"}'
  1. Observed, HTTP 400:
{"error":{"message":"{'error': 'Model with id=no-such-model-6842 not found in db'}","type":"invalid_request_error","param":null,"code":"400"}}

7. POST /model/update, model id that does not exist

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/model/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model_name":"lit6842-ghost","litellm_params":{"model":"openai/gpt-4o-mini"},"model_info":{"id":"no-such-model-6842"}}'
  1. Observed, HTTP 400:
{"error":{"message":"model not found","type":"invalid_request_error","param":null,"code":"400"}}

8. POST /model/new, same model_info.id twice, so the db write fails

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/model/new' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model_name":"lit6842-dup","litellm_params":{"model":"openai/gpt-4o-mini"},"model_info":{"id":"lit6842-fixed-id"}}'
  1. Observed, HTTP 500:
{"error":{"message":"{'error': 'Failed to add model to db. Check your server logs for more details.'}","type":"internal_server_error","param":null,"code":"500"}}

9. GET /health/services, service name that is not in the list

  1. Run:
curl -sS -X GET 'http://127.0.0.1:31620/health/services?service=not-a-service' -H 'Authorization: Bearer sk-1234'
  1. Observed, HTTP 400:
{"error":{"message":"{'error': \"Service must be in list. Service=not-a-service not in typing.Union[typing.Literal['slack_budget_alerts', 'langfuse', ...], str]\"}","type":"invalid_request_error","param":null,"code":"400"}}

10. POST /queue/chat/completions, no priority

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/queue/chat/completions' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model":"anthropic-haiku-4-5","messages":[{"role":"user","content":"hi"}]}'
  1. Observed, HTTP 400:
{"error":{"message":"Router.schedule_acompletion() missing 1 required positional argument: 'priority'","type":"invalid_request_error","param":null,"code":"400"}}

11. POST /queue/chat/completions, valid priority, model that does not exist

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/queue/chat/completions' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"model":"no-such-model-6842","messages":[{"role":"user","content":"hi"}],"priority":0}'
  1. Observed, HTTP 400:
{"error":{"message":"litellm.BadRequestError: You passed in model=no-such-model-6842. There are no healthy deployments for this model. Received Model Group=no-such-model-6842\nAvailable Model Group Fallbacks=None","type":"invalid_request_error","param":null,"code":"400"}}

12. POST /config/update, success_callback that is not a list of strings

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/config/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"litellm_settings":{"success_callback":[{"not":"a-string"}]}}'
  1. Observed, HTTP 400:
{"error":{"message":"unhashable type: 'dict'","type":"invalid_request_error","param":null,"code":"400"}}

13. GET /get/config/callbacks, after a scalar success_callback is stored

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/config/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' \
  -d '{"litellm_settings":{"success_callback":5}}'
curl -sS -X GET 'http://127.0.0.1:31620/get/config/callbacks' -H 'Authorization: Bearer sk-1234'
  1. Observed, HTTP 400:
{"error":{"message":"'int' object is not iterable","type":"invalid_request_error","param":null,"code":"400"}}

14. Auth control: GET /team/info with a key that does not exist

  1. Run:
curl -sS -X GET 'http://127.0.0.1:31620/team/info?team_id=whatever' -H 'Authorization: Bearer sk-not-a-real-key-6842'
  1. Observed, HTTP 401:
{"error":{"message":"Authentication Error, Invalid proxy server token passed. Received API Key = sk-...6842, Key Hash (Token) =249e3414...","type":"token_not_found_in_db","param":"key","code":"401"}}

15. Auth control: POST /login with the wrong password

  1. Run:
curl -sS -X POST 'http://127.0.0.1:31620/login' -d 'username=admin&password=definitely-wrong-6842'
  1. Observed, HTTP 401:
{"error":{"message":"Invalid credentials used to access UI.\nCheck 'UI_USERNAME', 'UI_PASSWORD' in .env file","type":"auth_error","param":"invalid_credentials","code":"401"}}

Notes from the two legs:

  • Every changed route kept its exact status and message body
  • The Authentication Error, message prefix is gone where it lied
  • /model/new duplicate-id answers 500, arguably should be a 409
  • /queue/chat/completions still leaks a raw Python TypeError text
  • /config/update stores a scalar success_callback that breaks reads

Type

🐛 Bug Fix

Caveats (if any)

Medium

  • Clients keying on type == "auth_error" see these 11 routes change
  • Every status code and message body stays exactly as it was
  • The Admin UI and litellm/proxy/client/ never branch on either type

Low

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

…ailures

Eleven management and health route handlers wrapped their body in a blanket
`except Exception` and raised `ProxyException(type=auth_error)` whatever actually
went wrong, so `/team/info` answered 404 with `type=auth_error` for a team that
does not exist and `/user/update` answered 400 for an unparseable
`budget_duration`, both on a valid admin key. `auth_error` is not an OpenAI error
type at all, so a client branching on `type` retried the credentials instead of
fixing the field.

Those handlers now read the type off the exception through a shared
`proxy_exception_for` helper, keeping the status each branch already answered
with. A `ProxyException` raised deliberately mid-request still passes through
with the type it named, so the 403 credential-attach authorization check keeps
`auth_error`. Every genuine auth site under `litellm/proxy/auth/` and
`ui_sso.py` is untouched
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR centralizes exception conversion for selected management and health endpoints so response error types reflect the underlying exception or HTTP status while preserving existing status codes.

  • Adds proxy_exception_for to preserve deliberate proxy exceptions and normalize other failures.
  • Replaces blanket auth_error responses across the targeted endpoints.
  • Adds unit and endpoint coverage for the revised error payloads.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
litellm/proxy/common_utils/openai_error_payload.py Adds the shared exception-to-proxy-error conversion helper and tests its status, type, parameter, and pass-through behavior.
litellm/proxy/health_endpoints/_health_endpoints.py Routes health-service failures through the shared helper instead of labeling every failure as authentication-related.
litellm/proxy/management_endpoints/internal_user_endpoints.py Updates /user/update error handling to derive an appropriate error type while retaining its existing default status.
litellm/proxy/management_endpoints/key_management_endpoints.py Updates /key/update to use shared error normalization and retain intentional proxy exceptions.
litellm/proxy/management_endpoints/model_management_endpoints.py Applies shared error normalization to the targeted model management handlers.
litellm/proxy/management_endpoints/organization_endpoints.py Preserves organization endpoint status codes while removing blanket authentication-error classification.
litellm/proxy/management_endpoints/team_endpoints.py Makes /team/info report the underlying request failure category rather than an authentication error.
litellm/proxy/proxy_server.py Applies the shared conversion helper to the targeted queue and configuration handlers.
tests/test_litellm/proxy/common_utils/test_openai_error_payload.py Covers helper behavior for proxy, HTTP, typed, untyped, and status-derived exceptions.
tests/test_litellm/proxy/management_endpoints/test_key_management_endpoints.py Adds endpoint regression coverage using a repository-supported test-quality suppression directive.

Reviews (2): Last reviewed commit: "fix(proxy): stop labelling management an..." | Re-trigger Greptile

@codecov

codecov Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@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 0c38a25. Configure here.

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.

2 participants