fix(proxy): make the lazy OpenAPI snapshot byte-identical on every Python version (#42519)

Python 3.13+ strips the common indentation of docstrings at compile time and 3.12
keeps it, and the 429 error description in ERROR_RESPONSES came straight from
RateLimitError.__doc__, so regenerating litellm/proxy/_lazy_openapi_snapshot.json
on a 3.13+ venv produced a one-line diff that the check-ui-api-types job (Python
3.12) rejected. Run the docstring through inspect.cleandoc before it lands in the
spec, regenerate the snapshot once, and pin the behavior with a test

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
This commit is contained in:
devin-ai-integration[bot] 2026-09-22 12:21:20 -07:00 • committed by GitHub
parent 2ef710e3d5
commit 569ccaece9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 25 additions and 2 deletions

View file

@ -19919,7 +19919,7 @@
}
}
},
"description": "\n Unified rate-limit error.\n\n Every rate-limit condition surfaced by litellm \u2014 whether it originated from\n an upstream LLM provider, a vendor batch endpoint, or one of litellm's own\n proxy-side limiters (parallel-requests, dynamic-rate, batch-rate, budget,\n max-iterations, etc.) \u2014 is raised as an instance of this class.\n\n The :attr:`category` attribute lets callers distinguish the source. See\n :class:`RateLimitErrorCategory` for the available values.\n "
"description": "Unified rate-limit error.\n\nEvery rate-limit condition surfaced by litellm \u2014 whether it originated from\nan upstream LLM provider, a vendor batch endpoint, or one of litellm's own\nproxy-side limiters (parallel-requests, dynamic-rate, batch-rate, budget,\nmax-iterations, etc.) \u2014 is raised as an instance of this class.\n\nThe :attr:`category` attribute lets callers distinguish the source. See\n:class:`RateLimitErrorCategory` for the available values."
},
"500": {
"content": {

View file

@ -1,3 +1,4 @@
import inspect
from typing import Any, Final
from pydantic import BaseModel, Field
@ -31,11 +32,15 @@ def get_status_code(exception):
return 500 # Internal Server Error as default
def _error_description(exception: type[Exception]) -> str:
return inspect.cleandoc(exception.__doc__) if exception.__doc__ else exception.__name__
# Create error responses
ERROR_RESPONSES: Final = {
get_status_code(exception): {
"model": ErrorResponse,
"description": exception.__doc__ or exception.__name__,
"description": _error_description(exception),
}
for exception in LITELLM_EXCEPTION_TYPES
}

View file

@ -0,0 +1,18 @@
import inspect
from litellm.exceptions import RateLimitError
from litellm.proxy.common_utils.swagger_utils import ERROR_RESPONSES, _error_description
class _ChildWithoutDoc(RateLimitError):
pass
def test_error_response_descriptions_carry_no_docstring_indentation():
assert ERROR_RESPONSES[429]["description"] == inspect.cleandoc(RateLimitError.__doc__ or "")
for response in ERROR_RESPONSES.values():
assert response["description"] == inspect.cleandoc(response["description"])
def test_error_description_falls_back_to_the_class_name_without_an_own_docstring():
assert _error_description(_ChildWithoutDoc) == "_ChildWithoutDoc"