Skip to content

fix(proxy): name shared-handler errors by the status they answer - #39555

Open
mateo-berri wants to merge 1 commit into
mainfrom
litellm_openai_error_type_from_status
Open

mateo-berri wants to merge 1 commit into
mainfrom
litellm_openai_error_type_from_status

Conversation

@mateo-berri

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

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Every management error was labelled internal_server_error
  • A 400 or 404 read to clients as a gateway outage
  • Retry loops that back off on 5xx spun forever
  • 15 routes across 6 endpoint families were affected
  • An exception with no status answered a bodiless 500

How it solves it:

  • Name the error type from the status actually answered
  • 400/404/409/422 become invalid_request_error
  • 401/403/429 become authentication/permission/rate-limit
  • Real 500s keep internal_server_error
  • An exception naming its own type keeps it
  • An exception with no status no longer crashes the error handler

User Flow

Before: a developer's provisioning script creates keys and teams through the gateway's management API, and every rejection of its own bad input comes back looking like the gateway is down, so the script's retry loop never stops

  1. They send POST https://litellm-domain/key/generate with {"budget_duration": "not-a-duration"}
  2. The reply is HTTP 400 carrying {"type":"internal_server_error","code":"400"}, saying the duration format is wrong
  3. Their client library branches on the type, sees a server-side failure, and retries with backoff
  4. Every retry sends the same bad duration and gets the same 400, so the script loops until it gives up on its own timeout, never surfacing the one-line typo
  5. They hit the same wall on POST https://litellm-domain/team/new with a duplicate team_id (400), on POST https://litellm-domain/user/new with a duplicate user_id (409), and on GET https://litellm-domain/credentials/by_name/ for a name that does not exist (404)

After: the same rejections identify themselves as bad requests, so the script stops on the first one and prints the actual problem

  1. They send the same POST https://litellm-domain/key/generate with {"budget_duration": "not-a-duration"}
  2. The reply is still HTTP 400, now carrying {"type":"invalid_request_error","code":"400"} with the same message about the duration format
  3. Their client library sees a client-side error, stops retrying, and surfaces the message on the first attempt
  4. They fix the duration to "30d" and the key is created
  5. The duplicate team_id, the duplicate user_id, and the missing credential name behave the same way: one attempt, invalid_request_error, the message they need
  6. A genuine gateway failure still answers internal_server_error, so the retry loop keeps working where retrying is the right thing to do

Relevant issues

Linear ticket

Resolves LIT-6839

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

Shared setup, identical for both legs: same config, same Postgres, same seeded rows, two uvicorn workers each, so the only difference between the two runs is the commit. Every PORT below was a random free high port, one per leg.

config.yaml:

model_list:
  - model_name: gpt-4o-mini
    litellm_params:
      model: openai/gpt-4o-mini
      api_key: os.environ/OPENAI_API_KEY

guardrails:
  - guardrail_name: grayswan-unreachable
    litellm_params:
      guardrail: grayswan
      mode: pre_call
      api_key: sk-fake-lit6839
      api_base: http://127.0.0.1:1
      fail_open: false

general_settings:
  master_key: sk-1234

Boot, run once per leg from that leg's own checkout:

python litellm/proxy/proxy_cli.py --config config.yaml --port PORT --num_workers 2

The t6839dup team, the u6839dup user and the c6839dup credential are created first so the duplicate-key probes have something to collide with. The grayswan-unreachable guardrail points at a port nothing listens on, which is how a real connection failure gets an exception carrying status_code=None into this handler.

Before (7a5b8bc)

Keys

  1. curl -sS -X POST 'http://127.0.0.1:PORT/key/generate' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"budget_duration":"not-a-duration"}'
{"error":{"message":"{'error': \"Invalid budget_duration 'not-a-duration'. Use a format like '1h', '24h', '7d', or '30d'.\"}","type":"internal_server_error","param":null,"code":"400"}}
HTTP 400
  1. curl -sS -X POST 'http://127.0.0.1:PORT/key/delete' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"keys":["sk-nonexistent-6839"]}'
{"error":{"message":"{'error': 'No keys found'}","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404

Teams

  1. curl -sS -X POST 'http://127.0.0.1:PORT/team/new' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"team_id":"t6839dup","team_alias":"t6839dup"}'
{"error":{"message":"{'error': 'Team id = t6839dup already exists. Please use a different team id.'}","type":"internal_server_error","param":null,"code":"400"}}
HTTP 400
  1. curl -sS -X POST 'http://127.0.0.1:PORT/team/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"team_id":"no-such-team-6839","team_alias":"x"}'
{"error":{"message":"{'error': 'Team not found, passed team_id=no-such-team-6839'}","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404
  1. curl -sS -X PATCH 'http://127.0.0.1:PORT/team/no-such-team-6839' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"team_alias":"x"}'
{"error":{"message":"{'error': 'Team not found, passed team_id=no-such-team-6839'}","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404

Internal users

  1. curl -sS -X POST 'http://127.0.0.1:PORT/user/new' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"user_id":"u6839dup","user_email":"u6839dup@example.com"}'
{"error":{"message":"{'error': 'User with id u6839dup already exists'}","type":"internal_server_error","param":null,"code":"409"}}
HTTP 409
  1. curl -sS -X GET 'http://127.0.0.1:PORT/user/info?user_id=no-such-user-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"User no-such-user-6839 not found","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404

Credentials

  1. curl -sS -X GET 'http://127.0.0.1:PORT/credentials/by_name/does-not-exist-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Credential not found. Got credential name: does-not-exist-6839","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404
  1. curl -sS -X GET 'http://127.0.0.1:PORT/credentials/by_model/no-such-model-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Model not found","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404

Guardrails

  1. curl -sS -X POST 'http://127.0.0.1:PORT/guardrails/apply_guardrail' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"guardrail_name":"no-such-guardrail-6839","text":"hi"}'
{"error":{"message":"Guardrail 'no-such-guardrail-6839' not found. Please ensure the guardrail is configured in your LiteLLM proxy.","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404

Batches

  1. curl -sS -X GET 'http://127.0.0.1:PORT/v1/batches/batch_nonexistent6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Error code: 404 - {'error': {'message': \"No batch found with id 'batch_nonexistent6839'.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404
  1. curl -sS -X POST 'http://127.0.0.1:PORT/v1/batches/batch_nonexistent6839/cancel' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Error code: 404 - {'error': {'message': \"No batch found with id 'batch_nonexistent6839'.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404
  1. curl -sS -X GET 'http://127.0.0.1:PORT/openai/v1/batches/batch_nonexistent6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Error code: 404 - {'error': {'message': \"No batch found with id 'batch_nonexistent6839'.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}","type":"internal_server_error","param":null,"code":"404"}}
HTTP 404

Unchanged: routes that raise ProxyException directly

  1. curl -sS -X GET 'http://127.0.0.1:PORT/key/info?key=sk-nonexistent-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Key not found in database","type":"not_found_error","param":"key","code":"404"}}
HTTP 404
  1. curl -sS -X GET 'http://127.0.0.1:PORT/customer/info?end_user_id=no-such-cust-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"End User Id=no-such-cust-6839 does not exist in db","type":"not_found","param":"end_user_id","code":"404"}}
HTTP 404
  1. curl -sS -X GET 'http://127.0.0.1:PORT/team/info?team_id=no-such-team-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"{'message': 'Team not found, passed team id: no-such-team-6839.'}","type":"auth_error","param":"None","code":"404"}}
HTTP 404
  1. curl -sS -X POST 'http://127.0.0.1:PORT/user/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"user_id":"u6839dup","budget_duration":"not-a-duration"}'
{"error":{"message":"{'error': \"Invalid budget_duration 'not-a-duration'. Use a format like '1h', '24h', '7d', or '30d'.\"}","type":"auth_error","param":"None","code":"400"}}
HTTP 400

Unchanged: a genuine 500

  1. curl -sS -X POST 'http://127.0.0.1:PORT/credentials' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"credential_name":"c6839dup","credential_values":{"api_key":"x"},"credential_info":{"a":"b"}}'
{"error":{"message":"Unique constraint failed on the fields: (`credential_name`)","type":"internal_server_error","param":null,"code":"500"}}
HTTP 500
  1. curl -sS -X GET 'http://127.0.0.1:PORT/global/spend/report?start_date=not-a-date&end_date=also-bad' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Internal server error","type":"internal_server_error"}}
HTTP 500

A guardrail whose upstream is unreachable

  1. curl -sS -X POST 'http://127.0.0.1:PORT/guardrails/apply_guardrail' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"guardrail_name":"grayswan-unreachable","text":"hi"}'
{"error":{"message":"Internal server error","type":"internal_server_error"}}
HTTP 500

Liveness, a real OpenAI call through the proxy

  1. curl -sS -X POST 'http://127.0.0.1:PORT/v1/chat/completions' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Reply with exactly: LIT-6839 QA leg live"}]}'
{"id":"chatcmpl-EK0E0wWeAOxzJdAcEiYaGFWZ9Xq4W","created":1788436132,"model":"gpt-4o-mini","object":"chat.completion","system_fingerprint":"fp_4ce87c02f6","choices":[{"finish_reason":"stop","index":0,"message":{"content":"LIT-6839 QA leg live","role":"assistant","provider_specific_fields":{"refusal":null},"annotations":[]},"provider_specific_fields":{}}],"usage":{"completion_tokens":8,"prompt_tokens":19,"total_tokens":27,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0}},"service_tier":"default"}
HTTP 200

After (6a9cb48)

Keys

  1. curl -sS -X POST 'http://127.0.0.1:PORT/key/generate' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"budget_duration":"not-a-duration"}'
{"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"}}
HTTP 400
  1. curl -sS -X POST 'http://127.0.0.1:PORT/key/delete' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"keys":["sk-nonexistent-6839"]}'
{"error":{"message":"{'error': 'No keys found'}","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404

Teams

  1. curl -sS -X POST 'http://127.0.0.1:PORT/team/new' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"team_id":"t6839dup","team_alias":"t6839dup"}'
{"error":{"message":"{'error': 'Team id = t6839dup already exists. Please use a different team id.'}","type":"invalid_request_error","param":null,"code":"400"}}
HTTP 400
  1. curl -sS -X POST 'http://127.0.0.1:PORT/team/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"team_id":"no-such-team-6839","team_alias":"x"}'
{"error":{"message":"{'error': 'Team not found, passed team_id=no-such-team-6839'}","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404
  1. curl -sS -X PATCH 'http://127.0.0.1:PORT/team/no-such-team-6839' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"team_alias":"x"}'
{"error":{"message":"{'error': 'Team not found, passed team_id=no-such-team-6839'}","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404

Internal users

  1. curl -sS -X POST 'http://127.0.0.1:PORT/user/new' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"user_id":"u6839dup","user_email":"u6839dup@example.com"}'
{"error":{"message":"{'error': 'User with id u6839dup already exists'}","type":"invalid_request_error","param":null,"code":"409"}}
HTTP 409
  1. curl -sS -X GET 'http://127.0.0.1:PORT/user/info?user_id=no-such-user-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"User no-such-user-6839 not found","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404

Credentials

  1. curl -sS -X GET 'http://127.0.0.1:PORT/credentials/by_name/does-not-exist-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Credential not found. Got credential name: does-not-exist-6839","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404
  1. curl -sS -X GET 'http://127.0.0.1:PORT/credentials/by_model/no-such-model-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Model not found","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404

Guardrails

  1. curl -sS -X POST 'http://127.0.0.1:PORT/guardrails/apply_guardrail' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"guardrail_name":"no-such-guardrail-6839","text":"hi"}'
{"error":{"message":"Guardrail 'no-such-guardrail-6839' not found. Please ensure the guardrail is configured in your LiteLLM proxy.","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404

Batches

  1. curl -sS -X GET 'http://127.0.0.1:PORT/v1/batches/batch_nonexistent6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Error code: 404 - {'error': {'message': \"No batch found with id 'batch_nonexistent6839'.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404
  1. curl -sS -X POST 'http://127.0.0.1:PORT/v1/batches/batch_nonexistent6839/cancel' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Error code: 404 - {'error': {'message': \"No batch found with id 'batch_nonexistent6839'.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404
  1. curl -sS -X GET 'http://127.0.0.1:PORT/openai/v1/batches/batch_nonexistent6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Error code: 404 - {'error': {'message': \"No batch found with id 'batch_nonexistent6839'.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}","type":"invalid_request_error","param":null,"code":"404"}}
HTTP 404

Unchanged: routes that raise ProxyException directly

  1. curl -sS -X GET 'http://127.0.0.1:PORT/key/info?key=sk-nonexistent-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Key not found in database","type":"not_found_error","param":"key","code":"404"}}
HTTP 404
  1. curl -sS -X GET 'http://127.0.0.1:PORT/customer/info?end_user_id=no-such-cust-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"End User Id=no-such-cust-6839 does not exist in db","type":"not_found","param":"end_user_id","code":"404"}}
HTTP 404
  1. curl -sS -X GET 'http://127.0.0.1:PORT/team/info?team_id=no-such-team-6839' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"{'message': 'Team not found, passed team id: no-such-team-6839.'}","type":"auth_error","param":"None","code":"404"}}
HTTP 404
  1. curl -sS -X POST 'http://127.0.0.1:PORT/user/update' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"user_id":"u6839dup","budget_duration":"not-a-duration"}'
{"error":{"message":"{'error': \"Invalid budget_duration 'not-a-duration'. Use a format like '1h', '24h', '7d', or '30d'.\"}","type":"auth_error","param":"None","code":"400"}}
HTTP 400

Unchanged: a genuine 500

  1. curl -sS -X POST 'http://127.0.0.1:PORT/credentials' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"credential_name":"c6839dup","credential_values":{"api_key":"x"},"credential_info":{"a":"b"}}'
{"error":{"message":"Unique constraint failed on the fields: (`credential_name`)","type":"internal_server_error","param":null,"code":"500"}}
HTTP 500
  1. curl -sS -X GET 'http://127.0.0.1:PORT/global/spend/report?start_date=not-a-date&end_date=also-bad' -H 'Authorization: Bearer sk-1234'
{"error":{"message":"Internal server error","type":"internal_server_error"}}
HTTP 500

A guardrail whose upstream is unreachable

  1. curl -sS -X POST 'http://127.0.0.1:PORT/guardrails/apply_guardrail' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"guardrail_name":"grayswan-unreachable","text":"hi"}'
{"error":{"message":"Cannot connect to host 127.0.0.1:1 ssl:<ssl.SSLContext object at 0x10cd40150> [Connect call failed ('127.0.0.1', 1)]","type":"internal_server_error","param":null,"code":"500"}}
HTTP 500

Liveness, a real OpenAI call through the proxy

  1. curl -sS -X POST 'http://127.0.0.1:PORT/v1/chat/completions' -H 'Authorization: Bearer sk-1234' -H 'Content-Type: application/json' -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Reply with exactly: LIT-6839 QA leg live"}]}'
{"id":"chatcmpl-EK0F1daneFJ58UBAixHURUBoTAJk2","created":1788436195,"model":"gpt-4o-mini","object":"chat.completion","system_fingerprint":"fp_4ce87c02f6","choices":[{"finish_reason":"stop","index":0,"message":{"content":"LIT-6839 QA leg live","role":"assistant","provider_specific_fields":{"refusal":null},"annotations":[]},"provider_specific_fields":{}}],"usage":{"completion_tokens":8,"prompt_tokens":19,"total_tokens":27,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0}},"service_tier":"default"}
HTTP 200

Type

🐛 Bug Fix

Caveats (if any)

Medium

  • Clients matching on the old type see a different string
    • Only on non-500s, which were mislabelled to begin with
    • The Admin UI is unaffected: it titles both types off the status
  • A 429 reaching this handler now answers throttling_error
    • That is the type LiteLLM already answers on the LLM routes
    • It comes from the exception naming itself, not the status map

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

Note

Medium Risk
Broad proxy error-path behavior change affects all routes using the shared handler; clients branching on error.type will see different strings on 4xx/429, though HTTP status and messages are unchanged.

Overview
handle_exception_on_proxy no longer labels every wrapped exception as internal_server_error. It now derives code via error_status_code and type via openai_error_type, so client errors (400/404/409/422 → invalid_request_error, 401/403/429 → auth/permission/rate-limit) match the status returned while true 5xx responses stay internal_server_error. Exceptions that already carry their own type (e.g. LiteLLM RateLimitErrorthrottling_error) are left unchanged.

Tests cover the handler mapping (including HTTP and status_code-carrying exceptions), an integration check that a missing credential lookup returns 404 with invalid_request_error, and updated expectations for 403 and custom status codes.

Reviewed by Cursor Bugbot for commit 6a9cb48. Bugbot is set up for automated code reviews on this repo. Configure here.

handle_exception_on_proxy pinned type=internal_server_error on every
exception it wrapped, so a management route rejecting a caller's own
argument answered {"type":"internal_server_error","code":"400"} and an
SDK branching on the type read its own bad request as a gateway outage.

Derive the type from the status the response actually carries, keeping
a type the exception already names.
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR updates the shared proxy exception handler so response error types reflect the effective HTTP status while preserving explicit exception types.

  • Uses shared error-payload helpers to normalize status codes, parameters, and OpenAI-compatible error types.
  • Adds coverage for common HTTP statuses, exceptions carrying status codes, explicit rate-limit types, and missing credential responses.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
litellm/proxy/utils.py Replaces unconditional internal-server classification with shared status-aware error normalization while retaining existing ProxyException instances.
tests/test_litellm/proxy/credential_endpoints/test_endpoints.py Adds an endpoint regression test confirming a missing credential is returned as a 404 invalid-request error.
tests/test_litellm/proxy/utils/helpers/test_error_helpers.py Expands unit coverage across client, authentication, permission, rate-limit, and server error classifications.

Reviews (2): Last reviewed commit: "fix(proxy): name shared-handler errors b..." | 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

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 6a9cb48. Configure here.

Base automatically changed from litellm_openai_error_payload_non_llm_routes to litellm_internal_staging September 8, 2026 23:41
@mateo-berri
mateo-berri requested a review from a team September 8, 2026 23:41
@yuneng-berri
yuneng-berri deleted the branch main September 13, 2026 04:48
@mateo-berri mateo-berri reopened this Sep 13, 2026
@mateo-berri
mateo-berri changed the base branch from litellm_internal_staging to main September 13, 2026 05:14
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.

3 participants