Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_daily_any_cleanup_08_03_2026

This commit is contained in:
mateo-berri 2026-08-03 20:03:30 -07:00
commit 1ae5297ef7
382 changed files with 12771 additions and 2719 deletions

View file

@ -88,6 +88,36 @@ commands:
rm -f /tmp/uv-install.sh
echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$BASH_ENV"
export PATH="$HOME/.local/bin:$PATH"
install_rust:
description: "Install pinned rustup (1.28.2) and Rust toolchain (1.97.1) with checksum verification. Adds ~/.cargo/bin to PATH. Run this before any `uv sync` or `uv build` of the workspace: the root package builds litellm-rust through maturin, and on an image without cargo maturin fetches an unpinned rustup and a floating toolchain by itself."
steps:
- run:
name: Install Rust (rustup 1.28.2, toolchain 1.97.1)
command: |
case "$(uname -m)" in
x86_64)
RUSTUP_TRIPLE=x86_64-unknown-linux-gnu
RUSTUP_SHA256=20a06e644b0d9bd2fbdbfd52d42540bdde820ea7df86e92e533c073da0cdd43c
;;
aarch64)
RUSTUP_TRIPLE=aarch64-unknown-linux-gnu
RUSTUP_SHA256=e3853c5a252fca15252d07cb23a1bdd9377a8c6f3efa01531109281ae47f841c
;;
*)
echo "install_rust: unsupported architecture $(uname -m)" >&2
exit 1
;;
esac
curl -sSLf -o /tmp/rustup-init \
"https://static.rust-lang.org/rustup/archive/1.28.2/${RUSTUP_TRIPLE}/rustup-init"
echo "${RUSTUP_SHA256} /tmp/rustup-init" | sha256sum -c -
chmod +x /tmp/rustup-init
/tmp/rustup-init -y --no-modify-path --profile minimal --default-toolchain 1.97.1
rm -f /tmp/rustup-init
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> "$BASH_ENV"
export PATH="$HOME/.cargo/bin:$PATH"
rustc --version
cargo --version
start_postgres:
description: "Start a postgres-db container on port 5432 and wait until it accepts connections."
parameters:
@ -163,6 +193,26 @@ commands:
done
echo "fake OpenAI endpoint did not become ready" >&2
exit 1
start_cost_center_service:
description: "Start the stand-in cost center validation service (tests/store_model_in_db_tests/cost_center_service.py) on host port 9414 and wait until healthy. The proxy's team-metadata validator (team_metadata_validator_e2e.py, impl 'http') reaches it via TEAM_METADATA_VALIDATION_SERVICE_URL=http://host.docker.internal:9414/validate. Run after uv deps are synced."
steps:
- run:
name: Start cost center validation service
background: true
command: |
uv run --no-sync python tests/store_model_in_db_tests/cost_center_service.py --host 0.0.0.0 --port 9414
- run:
name: Wait for cost center validation service
command: |
for i in $(seq 1 30); do
if curl -sf http://localhost:9414/health >/dev/null 2>&1; then
echo "cost center validation service is up"
exit 0
fi
sleep 1
done
echo "cost center validation service did not become ready" >&2
exit 1
setup_litellm_enterprise_pip:
steps:
- run:
@ -178,6 +228,7 @@ commands:
- checkout
- setup_google_dns
- install_uv
- install_rust
- restore_cache:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
@ -292,6 +343,7 @@ jobs:
- checkout
- setup_google_dns
- install_uv
- install_rust
- run:
name: Build the wheel
environment:
@ -324,6 +376,7 @@ jobs:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -397,6 +450,7 @@ jobs:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -471,6 +525,7 @@ jobs:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -522,6 +577,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -588,6 +644,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -628,6 +685,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -669,6 +727,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -702,6 +761,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- restore_cache:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
@ -752,6 +812,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- restore_cache:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
@ -803,6 +864,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -836,6 +898,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- restore_cache:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
@ -882,6 +945,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -928,6 +992,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -970,6 +1035,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1016,6 +1082,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1063,6 +1130,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- restore_cache:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
@ -1103,6 +1171,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1148,6 +1217,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1192,6 +1262,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1224,6 +1295,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1267,6 +1339,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1311,6 +1384,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1355,6 +1429,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1386,6 +1461,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1432,6 +1508,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1477,6 +1554,7 @@ jobs:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1527,6 +1605,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1551,6 +1630,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1577,6 +1657,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1678,6 +1759,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1773,6 +1855,7 @@ jobs:
at: ~/project
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1861,6 +1944,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -1944,6 +2028,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -2076,6 +2161,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -2162,6 +2248,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -2258,12 +2345,14 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
uv sync --frozen --all-groups --all-extras --python 3.12
- start_postgres
- start_fake_openai_endpoint
- start_cost_center_service
- attach_workspace:
at: ~/project
- run:
@ -2283,11 +2372,13 @@ jobs:
-e STORE_MODEL_IN_DB="True" \
-e LITELLM_MASTER_KEY="sk-1234" \
-e FAKE_OPENAI_API_BASE=http://host.docker.internal:8190 \
-e TEAM_METADATA_VALIDATION_SERVICE_URL=http://host.docker.internal:9414/validate \
-e LITELLM_LICENSE=$LITELLM_LICENSE \
-e LITELLM_LOG=ERROR \
--add-host host.docker.internal:host-gateway \
--name my-app \
-v $(pwd)/litellm/proxy/example_config_yaml/store_model_db_config.yaml:/app/config.yaml \
-v $(pwd)/litellm/proxy/example_config_yaml/team_metadata_validator_e2e.py:/app/team_metadata_validator_e2e.py \
litellm-docker-database:ci \
--config /app/config.yaml \
--port 4000
@ -2333,6 +2424,7 @@ jobs:
- setup_google_dns
# Remove Docker CLI installation since it's already available in machine executor
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -2414,6 +2506,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -2553,6 +2646,7 @@ jobs:
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- run:
name: Install Dependencies
command: |
@ -2743,6 +2837,7 @@ jobs:
category: client
- setup_google_dns
- install_uv
- install_rust
- restore_cache:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
@ -2885,6 +2980,7 @@ jobs:
category: client
- setup_google_dns
- install_uv
- install_rust
- restore_cache:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}

View file

@ -1,6 +1,6 @@
{
"reportAny": {
"limit": 29684
"limit": 29682
},
"reportArgumentType": {
"limit": 2645
@ -24,7 +24,7 @@
"limit": 42
},
"reportExplicitAny": {
"limit": 9442
"limit": 9440
},
"reportFunctionMemberAccess": {
"limit": 11

View file

@ -23,6 +23,7 @@ from typing import Any, cast
# Import all the data structures that define what can be lazy-loaded
# These are just lists of names and maps of where to find them
from ._lazy_imports_registry import (
# Import maps
_BEDROCK_TYPES_IMPORT_MAP,
_CACHING_IMPORT_MAP,
_COST_CALCULATOR_IMPORT_MAP,
@ -33,12 +34,11 @@ from ._lazy_imports_registry import (
_TOKEN_COUNTER_IMPORT_MAP,
_TYPES_IMPORT_MAP,
_TYPES_UTILS_IMPORT_MAP,
# Import maps
_UTILS_IMPORT_MAP,
_UTILS_MODULE_IMPORT_MAP,
# Name tuples
BEDROCK_TYPES_NAMES,
CACHING_NAMES,
# Name tuples
COST_CALCULATOR_NAMES,
DOTPROMPT_NAMES,
HTTP_HANDLER_NAMES,

View file

@ -249,7 +249,7 @@ def batch_completion_models_all_responses(*args, **kwargs):
if result is not None:
responses.append(result)
except Exception as e:
print_verbose(f"batch_completion_models_all_responses: model request failed: {e!s}")
print_verbose(f"batch_completion_models_all_responses: model request failed: {e}")
continue
return responses

View file

@ -182,7 +182,7 @@ def create_batch(
)
except Exception as e:
verbose_logger.exception(
f"litellm.batches.main.py::create_batch() - Error inferring custom_llm_provider - {e!s}"
f"litellm.batches.main.py::create_batch() - Error inferring custom_llm_provider - {e}"
)
_is_async = kwargs.pop("acreate_batch", False) is True
@ -890,7 +890,7 @@ def cancel_batch(
)
except Exception as e:
verbose_logger.exception(
f"litellm.batches.main.py::cancel_batch() - Error inferring custom_llm_provider - {e!s}"
f"litellm.batches.main.py::cancel_batch() - Error inferring custom_llm_provider - {e}"
)
optional_params = GenericLiteLLMParams(**kwargs)
litellm_params = get_litellm_params(

View file

@ -353,13 +353,13 @@ class Cache:
if param in combined_kwargs:
param_value: str | None = self._get_param_value(param, kwargs)
if param_value is not None:
cache_key += f"{param!s}: {param_value!s}"
cache_key += f"{param}: {param_value}"
elif param not in litellm_param_kwargs: # check if user passed in optional param - e.g. top_k
if litellm.enable_caching_on_provider_specific_optional_params is True: # feature flagged for now
if kwargs[param] is None:
continue # ignore None params
param_value = kwargs[param]
cache_key += f"{param!s}: {param_value!s}"
cache_key += f"{param}: {param_value}"
if is_semantic_cache:
cache_key += self._get_semantic_cache_tenant_scope(kwargs)
@ -676,7 +676,7 @@ class Cache:
cache_key, cached_data, kwargs = self._add_cache_logic(result=result, **kwargs)
self.cache.set_cache(cache_key, cached_data, **kwargs)
except Exception as e:
verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e!s}")
verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e}")
async def async_add_cache(self, result, dynamic_cache_object: BaseCache | None = None, **kwargs):
"""
@ -695,7 +695,7 @@ class Cache:
else:
await self.cache.async_set_cache(cache_key, cached_data, **kwargs)
except Exception as e:
verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e!s}")
verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e}")
def _convert_to_cached_embedding(
self,
@ -874,7 +874,7 @@ class Cache:
else:
await self.cache.async_set_cache_pipeline(cache_list=cache_list, **kwargs)
except Exception as e:
verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e!s}")
verbose_logger.exception(f"LiteLLM Cache: Excepton add_cache: {e}")
def should_use_cache(self, **kwargs):
"""

View file

@ -147,7 +147,7 @@ class DualCache(BaseCache):
return result
except Exception as e:
verbose_logger.error(f"LiteLLM Cache: Excepton async add_cache: {e!s}")
verbose_logger.error(f"LiteLLM Cache: Excepton async add_cache: {e}")
raise e
def get_cache(
@ -347,7 +347,7 @@ class DualCache(BaseCache):
if self.redis_cache is not None and local_only is False:
await self.redis_cache.async_set_cache(key, value, **kwargs)
except Exception as e:
verbose_logger.exception(f"LiteLLM Cache: Excepton async add_cache: {e!s}")
verbose_logger.exception(f"LiteLLM Cache: Excepton async add_cache: {e}")
# async_batch_set_cache
async def async_set_cache_pipeline(self, cache_list: list, local_only: bool = False, **kwargs):
@ -366,7 +366,7 @@ class DualCache(BaseCache):
cache_list=cache_list, ttl=kwargs.pop("ttl", None), **kwargs
)
except Exception as e:
verbose_logger.exception(f"LiteLLM Cache: Excepton async add_cache: {e!s}")
verbose_logger.exception(f"LiteLLM Cache: Excepton async add_cache: {e}")
async def async_increment_cache(
self,

View file

@ -0,0 +1,276 @@
"""
Deferred close of HTTP/SDK clients that the LLM client cache has evicted.
Eviction only drops the cache's reference to a client. Every OpenAI/Azure SDK
client is a reference cycle (each resource namespace holds the client back), so
an evicted client and its pooled TCP connections survive until a generational
collection runs, which under load is thousands of requests later.
Closing at eviction time is not an option: a request that was handed the client
just before it was evicted is still using it, and closing it underneath that
request raises ``RuntimeError: Cannot send a request, as the client has been
closed.``
So an evicted client is closed once two conditions hold. A grace window must
have passed since its eviction, which covers a request that holds the client
but is momentarily not on the wire, and the client must report no connection in
flight. The second condition is what keeps the first honest: a request may run
for ``litellm.request_timeout`` seconds, 6000 by default, and a streaming
response is bounded only by how long the upstream keeps sending, so no deadline
on its own can promise that a request has finished.
Only clients litellm itself created are closed; a client the caller supplied is
left alone because litellm does not own its lifecycle.
A client that closes synchronously is closed from wherever the cache is next
used. One whose close is a coroutine needs the event loop it was evicted on, so
it waits for a call from that loop rather than having work scheduled onto a loop
it does not belong to. Queued clients are therefore bucketed by what it takes to
close them, and each bucket is ordered by deadline, so a reap walks the entries
that are due rather than the whole queue.
The queue holds its clients weakly, so waiting out a grace window never keeps
alive anything the collector would have reclaimed first.
"""
import asyncio
import inspect
import threading
import time
import weakref
from collections import deque
from collections.abc import Awaitable, Callable, Iterator
from dataclasses import dataclass, replace
from litellm.constants import (
EVICTED_LLM_CLIENT_CLOSE_GRACE_SECONDS,
EVICTED_LLM_CLIENT_CLOSE_MAX_PENDING,
)
_CLOSABLE_ANYWHERE = "closable-anywhere"
_CLOSABLE_ON_ANY_LOOP = "closable-on-any-loop"
_BucketKey = str | int
@dataclass(frozen=True, slots=True)
class _PendingClose:
"""A queued close.
The client is held weakly, so queueing one never keeps alive anything the
collector would otherwise have reclaimed first.
``needs_loop`` is set for a client whose close is a coroutine; those can only
be closed from the event loop they were evicted on, recorded in ``loop_id``.
A client that closes synchronously carries neither constraint.
"""
client_ref: "weakref.ref[object]"
loop_id: int | None
needs_loop: bool
close_after: float
def _bucket_key(pending: _PendingClose) -> _BucketKey:
"""Which reaps can close this entry: any at all, any running a loop, or one loop's."""
if not pending.needs_loop:
return _CLOSABLE_ANYWHERE
if pending.loop_id is None:
return _CLOSABLE_ON_ANY_LOOP
return pending.loop_id
def _running_loop_id() -> int | None:
try:
return id(asyncio.get_running_loop())
except RuntimeError:
return None
def _close_function(client: object) -> Callable[[], object] | None:
close_fn: Callable[[], object] | None = getattr(client, "aclose", None) or getattr(client, "close", None)
return close_fn
def _transport_of(client: object) -> object:
"""The httpx transport behind an SDK wrapper, a litellm handler, or a bare client."""
for holder in (getattr(client, "_client", None), getattr(client, "client", None), client):
transport: object = getattr(holder, "_transport", None)
if transport is not None:
return transport
return None
def _connection_is_idle(connection: object) -> bool:
"""A pooled connection is idle unless it is servicing a request."""
is_idle: object = getattr(connection, "is_idle", None)
return bool(is_idle()) if callable(is_idle) else True
def _pool_has_busy_connection(transport: object) -> bool | None:
"""Whether the httpcore pool behind the transport is servicing a request.
``None`` when there is no such pool, so the caller can ask the other backend.
"""
pooled: object = getattr(getattr(transport, "_pool", None), "connections", None)
if not isinstance(pooled, (list, tuple)):
return None
return any(
not _connection_is_idle(connection) # pyright: ignore[reportUnknownArgumentType] # untyped pool list
for connection in pooled # pyright: ignore[reportUnknownVariableType] # untyped pool list
)
def _has_connection_in_flight(client: object) -> bool:
"""Whether the client is servicing a request right now.
Both connection backends litellm uses already account for the connections
they have handed out, so this reads the client's own lease accounting rather
than inferring it from elapsed time: httpcore reports a non-idle connection
for the whole of a response including a stream, and aiohttp holds the
connection in ``_acquired`` over the same span.
A client that cannot answer is reported as idle, which leaves the grace
window as the only guard, exactly as it was before this check existed.
"""
try:
transport = _transport_of(client)
pooled_busy = _pool_has_busy_connection(transport)
if pooled_busy is not None:
return pooled_busy
session: object = getattr(transport, "client", None)
return bool(getattr(getattr(session, "connector", None), "_acquired", None))
except Exception: # noqa: BLE001 - a client that cannot report its state is treated as idle
return False
async def _close_quietly(closing: Awaitable[object]) -> None:
try:
await closing
except Exception: # noqa: BLE001 - a discarded client's close must never surface to callers
pass
class EvictedClientCloser:
"""Closes evicted, litellm-owned clients once they are idle and out of grace."""
def __init__(
self,
grace_seconds: float = EVICTED_LLM_CLIENT_CLOSE_GRACE_SECONDS,
max_pending: int = EVICTED_LLM_CLIENT_CLOSE_MAX_PENDING,
clock: Callable[[], float] = time.monotonic,
) -> None:
self._grace_seconds = grace_seconds
self._max_pending = max_pending
self._clock = clock
self._owned: weakref.WeakSet[object] = weakref.WeakSet()
self._buckets: dict[_BucketKey, deque[_PendingClose]] = {} # mutable-ok: deadline-ordered queues
self._pending_count = 0
self._queue_lock = threading.Lock() # the cache is reachable from every worker thread's loop
self._close_tasks: set[asyncio.Task[None]] = set() # mutable-ok: strong refs to running closes
def mark_owned(self, client: object) -> None:
"""Record that litellm created this client, so it may be closed on eviction."""
try:
self._owned.add(client)
except TypeError:
pass # values that cannot be weak-referenced are never litellm clients
def _is_owned(self, client: object) -> bool:
try:
return client in self._owned
except TypeError:
return False # unhashable values are never litellm clients
def schedule(self, client: object) -> None:
"""Queue an evicted client for closing once it is idle and out of grace.
Past ``max_pending`` the client is left to the collector instead, so a
workload that churns the cache cannot grow this queue without bound.
Every queued entry comes due within one grace window, so the capacity it
occupies is returned within that window rather than held.
"""
if client is None or not self._is_owned(client):
return
close_fn = _close_function(client)
if close_fn is None:
return
if self._pending_count >= self._max_pending:
return
self._enqueue(
_PendingClose(
client_ref=weakref.ref(client),
loop_id=_running_loop_id(),
needs_loop=inspect.iscoroutinefunction(close_fn),
close_after=self._clock() + self._grace_seconds,
)
)
def reap(self) -> None:
"""Close every queued client that is due, idle, and closable from here.
Called from the cache's read path, so the empty-queue exit comes first and
the work done past it is proportional to what is due, not to the queue.
"""
if not self._pending_count:
return
now = self._clock()
for pending in self._take_due(_running_loop_id(), now):
client = pending.client_ref()
if client is None:
continue
if _has_connection_in_flight(client):
self._enqueue(replace(pending, close_after=now + self._grace_seconds))
continue
self._close(client)
@property
def pending_count(self) -> int:
return self._pending_count
def _enqueue(self, pending: _PendingClose) -> None:
"""Append to the entry's bucket, dropping any dead entries it queues behind.
Deadlines only ever move forward, so appending keeps each bucket ordered
by deadline, and entries whose client the collector already took sit at
the front rather than having to be searched for.
"""
with self._queue_lock:
bucket = self._buckets.setdefault(_bucket_key(pending), deque()) # mutable-ok: FIFO by design
while bucket and bucket[0].client_ref() is None:
bucket.popleft()
self._pending_count -= 1
bucket.append(pending)
self._pending_count += 1
def _take_due(self, loop_id: int | None, now: float) -> tuple[_PendingClose, ...]:
buckets = (_CLOSABLE_ANYWHERE,) if loop_id is None else (_CLOSABLE_ANYWHERE, _CLOSABLE_ON_ANY_LOOP, loop_id)
with self._queue_lock:
return tuple(pending for key in buckets for pending in self._drain_locked(key, now))
def _drain_locked(self, key: _BucketKey, now: float) -> Iterator[_PendingClose]:
bucket = self._buckets.get(key)
if bucket is None:
return
while bucket and bucket[0].close_after <= now:
self._pending_count -= 1
yield bucket.popleft()
if not bucket:
del self._buckets[key]
def _close(self, client: object) -> None:
close_fn = _close_function(client)
if close_fn is None:
return
try:
closing = close_fn()
except Exception: # noqa: BLE001 - a discarded client's close must never surface to callers
return
if not inspect.isawaitable(closing):
return
task = asyncio.get_running_loop().create_task(_close_quietly(closing))
self._close_tasks.add(task)
task.add_done_callback(self._close_tasks.discard)
default_evicted_client_closer = EvictedClientCloser()

View file

@ -4,21 +4,44 @@ Add the event loop to the cache key, to prevent event loop closed errors.
import asyncio
from .evicted_client_closer import EvictedClientCloser, default_evicted_client_closer
from .in_memory_cache import InMemoryCache
class LLMClientCache(InMemoryCache):
"""Cache for LLM HTTP clients (OpenAI, Azure, httpx, etc.).
IMPORTANT: This cache intentionally does NOT close clients on eviction.
Evicted clients may still be in use by in-flight requests. Closing them
eagerly causes ``RuntimeError: Cannot send a request, as the client has
been closed.`` errors in production after the TTL (1 hour) expires.
An evicted client is never closed on the spot: a request handed the client
just before eviction is still using it, and closing it there raises
``RuntimeError: Cannot send a request, as the client has been closed.``
Clients that are no longer referenced will be garbage-collected normally.
For explicit shutdown cleanup, use ``close_litellm_async_clients()``.
Nor can eviction be left to rely on garbage collection. The SDK clients are
reference cycles, so an evicted client and its open TCP connections survive
until a generational collection runs. Instead a client litellm created is
handed to ``EvictedClientCloser``, which closes it once a grace window has
passed. Clients the caller supplied are left untouched.
"""
def __init__(
self,
max_size_in_memory: int | None = 200,
default_ttl: int | None = 600,
max_size_per_item: int | None = 1024,
evicted_client_closer: EvictedClientCloser | None = None,
):
super().__init__(
max_size_in_memory=max_size_in_memory,
default_ttl=default_ttl,
max_size_per_item=max_size_per_item,
)
self.evicted_client_closer = evicted_client_closer or default_evicted_client_closer
def _remove_key(self, key: str) -> None:
evicted: object = self.cache_dict.get(key)
super()._remove_key(key)
self.evicted_client_closer.schedule(evicted)
self.evicted_client_closer.reap()
def update_cache_key_with_event_loop(self, key):
"""
Add the event loop to the cache key, to prevent event loop closed errors.
@ -31,16 +54,22 @@ class LLMClientCache(InMemoryCache):
except RuntimeError: # handle no current running event loop
return key
def set_cache(self, key, value, **kwargs):
def set_cache(self, key: str, value: object, litellm_owned_client: bool = False, **kwargs):
"""``litellm_owned_client`` marks a client litellm built, so it may be closed once evicted."""
if litellm_owned_client:
self.evicted_client_closer.mark_owned(value)
key = self.update_cache_key_with_event_loop(key)
return super().set_cache(key, value, **kwargs)
async def async_set_cache(self, key, value, **kwargs):
async def async_set_cache(self, key: str, value: object, litellm_owned_client: bool = False, **kwargs):
if litellm_owned_client:
self.evicted_client_closer.mark_owned(value)
key = self.update_cache_key_with_event_loop(key)
return await super().async_set_cache(key, value, **kwargs)
def get_cache(self, key, **kwargs):
key = self.update_cache_key_with_event_loop(key)
self.evicted_client_closer.reap()
return super().get_cache(key, **kwargs)

View file

@ -178,7 +178,7 @@ class QdrantSemanticCache(BaseCache):
if response.status_code not in (200, 201):
print_verbose(f"Qdrant semantic-cache could not create cache-key payload index: {response.text}")
except Exception as exc:
print_verbose(f"Qdrant semantic-cache could not create cache-key payload index: {exc!s}")
print_verbose(f"Qdrant semantic-cache could not create cache-key payload index: {exc}")
def _payload_matches_cache_key(self, payload: dict, key: str) -> bool:
# Pre-isolation points stored only prompt + response with no cache-key

View file

@ -346,7 +346,7 @@ class RedisCache(BaseCache):
verbose_logger.debug("Ignoring async redis ping. No running event loop.")
else:
verbose_logger.error(
f"Error connecting to Async Redis client - {e!s}",
f"Error connecting to Async Redis client - {e}",
extra={"error": str(e)},
)
self._handle_async_ping_error(e)
@ -483,7 +483,7 @@ class RedisCache(BaseCache):
)
except Exception as e:
# NON blocking - notify users Redis is throwing an exception
print_verbose(f"litellm.caching.caching: set() - Got exception from REDIS : {e!s}")
print_verbose(f"litellm.caching.caching: set() - Got exception from REDIS : {e}")
def increment_cache(self, key, value: int, ttl: float | None = None, **kwargs) -> int:
_redis_client = self.redis_client
@ -1139,7 +1139,7 @@ class RedisCache(BaseCache):
return decoded_results
except Exception as e:
verbose_logger.error(f"Error occurred in batch get cache - {e!s}")
verbose_logger.error(f"Error occurred in batch get cache - {e}")
return key_value_dict
@_redis_circuit_breaker_guard
@ -1185,7 +1185,7 @@ class RedisCache(BaseCache):
event_metadata={"key": key},
)
)
print_verbose(f"litellm.caching.caching: async get() - Got exception from REDIS: {e!s}")
print_verbose(f"litellm.caching.caching: async get() - Got exception from REDIS: {e}")
_record_swallowed_redis_failure(self._circuit_breaker, e)
@_redis_circuit_breaker_guard
@ -1257,7 +1257,7 @@ class RedisCache(BaseCache):
parent_otel_span=parent_otel_span,
)
)
verbose_logger.error(f"Error occurred in async batch get cache - {e!s}")
verbose_logger.error(f"Error occurred in async batch get cache - {e}")
_record_swallowed_redis_failure(self._circuit_breaker, e)
return key_value_dict
@ -1292,7 +1292,7 @@ class RedisCache(BaseCache):
error=e,
call_type=f"sync_ping <- {_get_call_stack_info()}",
)
verbose_logger.error(f"LiteLLM Redis Cache PING: - Got exception from REDIS : {e!s}")
verbose_logger.error(f"LiteLLM Redis Cache PING: - Got exception from REDIS : {e}")
raise e
async def ping(self) -> bool:
@ -1326,7 +1326,7 @@ class RedisCache(BaseCache):
call_type=f"async_ping <- {_get_call_stack_info()}",
)
)
verbose_logger.error(f"LiteLLM Redis Cache PING: - Got exception from REDIS : {e!s}")
verbose_logger.error(f"LiteLLM Redis Cache PING: - Got exception from REDIS : {e}")
raise e
@_redis_circuit_breaker_guard
@ -1388,10 +1388,10 @@ class RedisCache(BaseCache):
else:
return {"status": "failed", "message": "Redis ping returned False"}
except Exception as e:
verbose_logger.error(f"Redis connection test failed: {e!s}")
verbose_logger.error(f"Redis connection test failed: {e}")
return {
"status": "failed",
"message": f"Redis connection failed: {e!s}",
"message": f"Redis connection failed: {e}",
"error": str(e),
}
@ -1565,7 +1565,7 @@ class RedisCache(BaseCache):
call_type=f"async_rpush <- {_get_call_stack_info()}",
)
)
verbose_logger.error(f"LiteLLM Redis Cache RPUSH: - Got exception from REDIS : {e!s}")
verbose_logger.error(f"LiteLLM Redis Cache RPUSH: - Got exception from REDIS : {e}")
raise e
async def _pipeline_rpush_helper(
@ -1711,7 +1711,7 @@ class RedisCache(BaseCache):
call_type=f"async_lpop <- {_get_call_stack_info()}",
)
)
verbose_logger.error(f"LiteLLM Redis Cache LPOP: - Got exception from REDIS : {e!s}")
verbose_logger.error(f"LiteLLM Redis Cache LPOP: - Got exception from REDIS : {e}")
raise e
async def _pipeline_lpop_helper(

View file

@ -100,9 +100,9 @@ class RedisClusterCache(RedisCache):
except Exception as e:
from litellm._logging import verbose_logger
verbose_logger.error(f"Redis Cluster connection test failed: {e!s}")
verbose_logger.error(f"Redis Cluster connection test failed: {e}")
return {
"status": "failed",
"message": f"Redis Cluster connection failed: {e!s}",
"message": f"Redis Cluster connection failed: {e}",
"error": str(e),
}

View file

@ -364,7 +364,7 @@ class RedisSemanticCache(BaseCache):
try:
cached_response = ast.literal_eval(cached_response)
except (ValueError, SyntaxError) as e:
print_verbose(f"Error parsing cached response: {e!s}")
print_verbose(f"Error parsing cached response: {e}")
return None
return cached_response
@ -403,7 +403,7 @@ class RedisSemanticCache(BaseCache):
store_kwargs["ttl"] = int(ttl)
self.llmcache.store(prompt, value_str, **store_kwargs)
except Exception as e:
print_verbose(f"Error setting {value_str or value} in the Redis semantic cache: {e!s}")
print_verbose(f"Error setting {value_str or value} in the Redis semantic cache: {e}")
def get_cache(self, key: str, **kwargs) -> Any:
"""
@ -468,7 +468,7 @@ class RedisSemanticCache(BaseCache):
return self._get_cache_logic(cached_response=cached_response)
except Exception as e:
print_verbose(f"Error retrieving from Redis semantic cache: {e!s}")
print_verbose(f"Error retrieving from Redis semantic cache: {e}")
kwargs.setdefault("metadata", {})["semantic-similarity"] = 0.0
async def _get_async_embedding(self, prompt: str, metadata: dict[str, Any] | None = None) -> list[float]:
@ -505,8 +505,8 @@ class RedisSemanticCache(BaseCache):
)
return embedding_response["data"][0]["embedding"]
except Exception as e:
print_verbose(f"Error generating async embedding: {e!s}")
raise ValueError(f"Failed to generate embedding: {e!s}") from e
print_verbose(f"Error generating async embedding: {e}")
raise ValueError(f"Failed to generate embedding: {e}") from e
async def async_set_cache(self, key: str, value: Any, **kwargs) -> None:
"""
@ -546,7 +546,7 @@ class RedisSemanticCache(BaseCache):
**store_kwargs,
)
except Exception as e:
print_verbose(f"Error in async_set_cache: {e!s}")
print_verbose(f"Error in async_set_cache: {e}")
async def async_get_cache(self, key: str, **kwargs) -> Any:
"""
@ -612,7 +612,7 @@ class RedisSemanticCache(BaseCache):
return self._get_cache_logic(cached_response=cached_response)
except Exception as e:
print_verbose(f"Error in async_get_cache: {e!s}")
print_verbose(f"Error in async_get_cache: {e}")
kwargs.setdefault("metadata", {})["semantic-similarity"] = 0.0
async def _index_info(self) -> dict[str, Any]:
@ -639,4 +639,4 @@ class RedisSemanticCache(BaseCache):
tasks.append(self.async_set_cache(val[0], val[1], **kwargs))
await asyncio.gather(*tasks)
except Exception as e:
print_verbose(f"Error in async_set_cache_pipeline: {e!s}")
print_verbose(f"Error in async_set_cache_pipeline: {e}")

View file

@ -249,7 +249,7 @@ class ValkeySemanticCache(RedisSemanticCache):
if ttl is not None:
self.sync_client.expire(doc_key, ttl)
except Exception as e:
print_verbose(f"Error in Valkey semantic-cache set_cache: {e!s}")
print_verbose(f"Error in Valkey semantic-cache set_cache: {e}")
def get_cache(self, key: str, **kwargs: Any) -> Any:
print_verbose(f"Valkey semantic-cache get_cache, kwargs: {kwargs}")
@ -268,7 +268,7 @@ class ValkeySemanticCache(RedisSemanticCache):
)
return self._resolve_hit(self._first_hit(search_result), key, **kwargs)
except Exception as e:
print_verbose(f"Error in Valkey semantic-cache get_cache: {e!s}")
print_verbose(f"Error in Valkey semantic-cache get_cache: {e}")
kwargs.setdefault("metadata", {})["semantic-similarity"] = 0.0
async def async_set_cache(self, key: str, value: Any, **kwargs: Any) -> None:
@ -288,7 +288,7 @@ class ValkeySemanticCache(RedisSemanticCache):
if ttl is not None:
await self.async_client.expire(doc_key, ttl)
except Exception as e:
print_verbose(f"Error in async Valkey semantic-cache set_cache: {e!s}")
print_verbose(f"Error in async Valkey semantic-cache set_cache: {e}")
async def async_get_cache(self, key: str, **kwargs: Any) -> Any:
print_verbose(f"Async Valkey semantic-cache get_cache, kwargs: {kwargs}")
@ -307,14 +307,14 @@ class ValkeySemanticCache(RedisSemanticCache):
)
return self._resolve_hit(self._first_hit(search_result), key, **kwargs)
except Exception as e:
print_verbose(f"Error in async Valkey semantic-cache get_cache: {e!s}")
print_verbose(f"Error in async Valkey semantic-cache get_cache: {e}")
kwargs.setdefault("metadata", {})["semantic-similarity"] = 0.0
async def async_set_cache_pipeline(self, cache_list: list[tuple[str, Any]], **kwargs: Any) -> None:
try:
await asyncio.gather(*[self.async_set_cache(key, value, **kwargs) for key, value in cache_list])
except Exception as e:
print_verbose(f"Error in Valkey semantic-cache async_set_cache_pipeline: {e!s}")
print_verbose(f"Error in Valkey semantic-cache async_set_cache_pipeline: {e}")
async def _index_info(self) -> dict:
return await self.async_client.ft(self.index_name).info()

View file

@ -197,6 +197,16 @@ RUNWAYML_POLLING_TIMEOUT = int(os.getenv("RUNWAYML_POLLING_TIMEOUT", 600)) # 10
########## Networking constants ##############################################################
_DEFAULT_TTL_FOR_HTTPX_CLIENTS = 3600 # 1 hour, re-use the same httpx client for 1 hour
# The earliest an evicted, litellm-created client may be closed. A request handed the
# client just before eviction is still using it, so nothing is closed inside this window;
# past it, the client is closed once it reports no connection in flight.
EVICTED_LLM_CLIENT_CLOSE_GRACE_SECONDS = 900
# How many evicted clients may be queued for closing at once. Past this, an evicted client
# is left to the collector rather than letting a cache-churning workload grow the queue
# without bound. Each queued entry is ~100 bytes and comes due within one grace window.
EVICTED_LLM_CLIENT_CLOSE_MAX_PENDING = 10_000
# Aiohttp connection pooling - prevents memory leaks from unbounded connection growth
# Set to 0 for unlimited (not recommended for production)
AIOHTTP_CONNECTOR_LIMIT = int(os.getenv("AIOHTTP_CONNECTOR_LIMIT", 1000))

View file

@ -715,7 +715,7 @@ def _get_provider_for_cost_calc(
_, custom_llm_provider, _, _ = litellm.get_llm_provider(model=model)
except Exception as e:
verbose_logger.debug(
f"litellm.cost_calculator.py::_get_provider_for_cost_calc() - Error inferring custom_llm_provider - {e!s}"
f"litellm.cost_calculator.py::_get_provider_for_cost_calc() - Error inferring custom_llm_provider - {e}"
)
return None
@ -1092,7 +1092,7 @@ def _store_cost_breakdown_in_logging_obj(
)
except Exception as breakdown_error:
verbose_logger.debug(f"Error storing cost breakdown: {breakdown_error!s}")
verbose_logger.debug(f"Error storing cost breakdown: {breakdown_error}")
# Don't fail the main cost calculation if breakdown storage fails
@ -1315,7 +1315,7 @@ def completion_cost(
) # strip the llm provider from the model name -> for image gen cost calculation
except Exception as e:
verbose_logger.debug(
f"litellm.cost_calculator.py::completion_cost() - Error inferring custom_llm_provider - {e!s}"
f"litellm.cost_calculator.py::completion_cost() - Error inferring custom_llm_provider - {e}"
)
if CostCalculatorUtils._call_type_has_image_response(call_type) and isinstance(
completion_response, ImageResponse
@ -1662,7 +1662,7 @@ def completion_cost(
return _final_cost
except Exception as e:
verbose_logger.debug(
f"litellm.cost_calculator.py::completion_cost() - Error calculating cost for model={model} - {e!s}"
f"litellm.cost_calculator.py::completion_cost() - Error calculating cost for model={model} - {e}"
)
if idx == len(potential_model_names) - 1:
raise e

View file

@ -1140,7 +1140,7 @@ class MidStreamFallbackError(ServiceUnavailableError): # type: ignore
if self.max_retries:
_message += f", LiteLLM Max Retries: {self.max_retries}"
if self.original_exception:
_message += f" Original exception: {type(self.original_exception).__name__}: {self.original_exception!s}"
_message += f" Original exception: {type(self.original_exception).__name__}: {self.original_exception}"
return _message
def __repr__(self):

View file

@ -515,7 +515,7 @@ class MCPClient:
_log(
f"MCP client list_tools failed - "
f"Error Type: {error_type}, "
f"Error: {e!s}, "
f"Error: {e}, "
f"Server: {self.server_url or 'stdio'}, "
f"Transport: {self.transport_type}"
)
@ -536,7 +536,7 @@ class MCPClient:
def error_tool_result(exc: Exception) -> MCPCallToolResult:
"""The error result ``call_tool`` returns when it swallows a failure (no re-execution)."""
return MCPCallToolResult(
content=[TextContent(type="text", text=f"{type(exc).__name__}: {exc!s}")],
content=[TextContent(type="text", text=f"{type(exc).__name__}: {exc}")],
isError=True,
)
@ -601,7 +601,7 @@ class MCPClient:
_log(
f"MCP client call_tool failed - "
f"Error Type: {error_type}, "
f"Error: {e!s}, "
f"Error: {e}, "
f"Tool: {call_tool_request_params.name}, "
f"Server: {self.server_url or 'stdio'}, "
f"Transport: {self.transport_type}"
@ -640,7 +640,7 @@ class MCPClient:
verbose_logger.error(
f"MCP client list_prompts failed - "
f"Error Type: {error_type}, "
f"Error: {e!s}, "
f"Error: {e}, "
f"Server: {self.server_url or 'stdio'}, "
f"Transport: {self.transport_type}"
)
@ -681,7 +681,7 @@ class MCPClient:
verbose_logger.error(
f"MCP client get_prompt failed - "
f"Error Type: {error_type}, "
f"Error: {e!s}, "
f"Error: {e}, "
f"Prompt: {get_prompt_request_params.name}, "
f"Server: {self.server_url or 'stdio'}, "
f"Transport: {self.transport_type}"
@ -717,7 +717,7 @@ class MCPClient:
verbose_logger.error(
f"MCP client list_resources failed - "
f"Error Type: {error_type}, "
f"Error: {e!s}, "
f"Error: {e}, "
f"Server: {self.server_url or 'stdio'}, "
f"Transport: {self.transport_type}"
)
@ -753,7 +753,7 @@ class MCPClient:
verbose_logger.error(
f"MCP client list_resource_templates failed - "
f"Error Type: {error_type}, "
f"Error: {e!s}, "
f"Error: {e}, "
f"Server: {self.server_url or 'stdio'}, "
f"Transport: {self.transport_type}"
)
@ -791,7 +791,7 @@ class MCPClient:
verbose_logger.error(
f"MCP client read_resource failed - "
f"Error Type: {error_type}, "
f"Error: {e!s}, "
f"Error: {e}, "
f"Url: {url}, "
f"Server: {self.server_url or 'stdio'}, "
f"Transport: {self.transport_type}"

View file

@ -98,7 +98,7 @@ class GenerateContentToCompletionHandler:
return generate_content_response
except Exception as e:
raise ValueError(f"Error calling litellm.acompletion for generate_content: {e!s}")
raise ValueError(f"Error calling litellm.acompletion for generate_content: {e}")
@staticmethod
def generate_content_handler(
@ -159,4 +159,4 @@ class GenerateContentToCompletionHandler:
return generate_content_response
except Exception as e:
raise ValueError(f"Error calling litellm.completion for generate_content: {e!s}")
raise ValueError(f"Error calling litellm.completion for generate_content: {e}")

View file

@ -70,6 +70,6 @@ async def send_to_webhook(slackAlertingInstance: SlackAlertingType, item, count)
if response.status_code != 200:
verbose_proxy_logger.debug(f"Error sending slack alert to url={item['url']}. Error={response.text}")
except Exception as e:
verbose_proxy_logger.debug(f"Error sending slack alert: {e!s}")
verbose_proxy_logger.debug(f"Error sending slack alert: {e}")
finally:
_print_alerting_payload_warning(payload, slackAlertingInstance=slackAlertingInstance)

View file

@ -1467,7 +1467,7 @@ Model Info:
try:
await self._flush_digest_buckets()
except Exception as e:
verbose_proxy_logger.debug(f"Error flushing digest buckets: {e!s}")
verbose_proxy_logger.debug(f"Error flushing digest buckets: {e}")
await self.flush_queue()
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
@ -1502,7 +1502,7 @@ Model Info:
)
except Exception as e:
verbose_proxy_logger.error(
f"[Non-Blocking Error] Slack Alerting: Got error in logging LLM deployment latency: {e!s}"
f"[Non-Blocking Error] Slack Alerting: Got error in logging LLM deployment latency: {e}"
)
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
@ -1522,7 +1522,7 @@ Model Info:
)
)
except Exception as e:
verbose_logger.debug(f"Exception raises -{e!s}")
verbose_logger.debug(f"Exception raises -{e}")
if isinstance(kwargs.get("exception", ""), APIError):
if "outage_alerts" in self.alert_types:

View file

@ -169,7 +169,7 @@ class ArizeLogger(OpenTelemetry):
except Exception as e:
return {
"status": "unhealthy",
"error_message": f"Arize health check failed: {e!s}",
"error_message": f"Arize health check failed: {e}",
}
def construct_dynamic_otel_headers(

View file

@ -203,7 +203,7 @@ class AzureSentinelLogger(CustomBatchLogger):
await self.async_send_batch()
except Exception as e:
verbose_logger.exception(f"Azure Sentinel Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Azure Sentinel Layer Error - {e}\n{traceback.format_exc()}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
"""
@ -233,7 +233,7 @@ class AzureSentinelLogger(CustomBatchLogger):
await self.async_send_batch()
except Exception as e:
verbose_logger.exception(f"Azure Sentinel Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Azure Sentinel Layer Error - {e}\n{traceback.format_exc()}")
async def async_log_audit_log_event(self, audit_log: StandardAuditLogPayload) -> None:
"""
@ -256,7 +256,7 @@ class AzureSentinelLogger(CustomBatchLogger):
await self.async_send_audit_batch()
except Exception as e:
verbose_logger.exception(f"Azure Sentinel Audit Log Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Azure Sentinel Audit Log Layer Error - {e}\n{traceback.format_exc()}")
async def async_send_batch(self):
"""
@ -323,7 +323,7 @@ class AzureSentinelLogger(CustomBatchLogger):
)
except Exception as e:
verbose_logger.exception(f"Azure Sentinel Error sending batch API - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Azure Sentinel Error sending batch API - {e}\n{traceback.format_exc()}")
finally:
log_queue.clear()

View file

@ -53,9 +53,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
self.log_queue: list[StandardLoggingPayload] = []
super().__init__(**kwargs, flush_lock=self.flush_lock)
except Exception as e:
verbose_logger.exception(
f"AzureBlobStorageLogger: Got exception on init AzureBlobStorageLogger client {e!s}"
)
verbose_logger.exception(f"AzureBlobStorageLogger: Got exception on init AzureBlobStorageLogger client {e}")
raise e
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
@ -79,7 +77,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
self.log_queue.append(standard_logging_payload)
except Exception as e:
verbose_logger.exception(f"AzureBlobStorageLogger Layer Error - {e!s}")
verbose_logger.exception(f"AzureBlobStorageLogger Layer Error - {e}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
"""
@ -101,7 +99,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
self.log_queue.append(standard_logging_payload)
except Exception as e:
verbose_logger.exception(f"AzureBlobStorageLogger Layer Error - {e!s}")
verbose_logger.exception(f"AzureBlobStorageLogger Layer Error - {e}")
async def async_send_batch(self):
"""
@ -124,7 +122,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
await self.async_upload_payload_to_azure_blob_storage(payload=payload)
except Exception as e:
verbose_logger.exception(f"AzureBlobStorageLogger Error sending batch API - {e!s}")
verbose_logger.exception(f"AzureBlobStorageLogger Error sending batch API - {e}")
async def async_upload_payload_to_azure_blob_storage(self, payload: StandardLoggingPayload):
"""
@ -153,7 +151,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
verbose_logger.debug(f"Successfully uploaded log to Azure Blob Storage: {filename}")
except Exception as e:
verbose_logger.exception(f"Error uploading to Azure Blob Storage: {e!s}")
verbose_logger.exception(f"Error uploading to Azure Blob Storage: {e}")
raise e
async def _create_file(self, client: AsyncHTTPHandler, base_url: str):
@ -169,7 +167,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
response.raise_for_status()
verbose_logger.debug("Successfully created file resource")
except Exception as e:
verbose_logger.exception(f"Error creating file resource: {e!s}")
verbose_logger.exception(f"Error creating file resource: {e}")
raise
async def _append_data(self, client: AsyncHTTPHandler, base_url: str, json_payload: str):
@ -189,7 +187,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
response.raise_for_status()
verbose_logger.debug("Successfully appended data")
except Exception as e:
verbose_logger.exception(f"Error appending data: {e!s}")
verbose_logger.exception(f"Error appending data: {e}")
raise
async def _flush_data(self, client: AsyncHTTPHandler, base_url: str, position: int):
@ -205,7 +203,7 @@ class AzureBlobStorageLogger(CustomBatchLogger):
response.raise_for_status()
verbose_logger.debug("Successfully flushed data")
except Exception as e:
verbose_logger.exception(f"Error flushing data: {e!s}")
verbose_logger.exception(f"Error flushing data: {e}")
raise
####### Helper methods to managing Authentication to Azure Storage #######
@ -345,4 +343,4 @@ class AzureBlobStorageLogger(CustomBatchLogger):
verbose_logger.debug(f"Successfully uploaded and wrote to {today}/{file_name}")
except Exception as e:
verbose_logger.exception(f"Error occurred: {e!s}")
verbose_logger.exception(f"Error occurred: {e}")

View file

@ -153,7 +153,7 @@ class CloudZeroLogger(CustomLogger):
verbose_logger.debug(f"CloudZero Logger: Successfully exported {len(cbf_data)} records to CloudZero")
except Exception as e:
verbose_logger.error(f"CloudZero Logger: Error exporting usage data: {e!s}")
verbose_logger.error(f"CloudZero Logger: Error exporting usage data: {e}")
raise
async def dry_run_export_usage_data(self, limit: int | None = 10000):
@ -244,8 +244,8 @@ class CloudZeroLogger(CustomLogger):
}
except Exception as e:
verbose_logger.error(f"CloudZero Logger: Error in dry run export: {e!s}")
verbose_logger.error(f"CloudZero Dry Run Error: {e!s}")
verbose_logger.error(f"CloudZero Logger: Error in dry run export: {e}")
verbose_logger.error(f"CloudZero Dry Run Error: {e}")
raise
def _display_cbf_data_on_screen(self, cbf_data):

View file

@ -98,4 +98,4 @@ class LiteLLMDatabase:
# This prevents schema mismatch errors when data types vary across rows
return pl.DataFrame(db_response, infer_schema_length=None)
except Exception as e:
raise Exception(f"Error retrieving usage data: {e!s}")
raise Exception(f"Error retrieving usage data: {e}")

View file

@ -927,7 +927,7 @@ class CustomLogger: # https://docs.litellm.ai/docs/observability/custom_callbac
except Exception as e:
from litellm._logging import verbose_logger
verbose_logger.debug(f"Error in handle_callback_failure for {callback_name}: {e!s}")
verbose_logger.debug(f"Error in handle_callback_failure for {callback_name}: {e}")
async def _strip_base64_from_messages(
self,

View file

@ -171,7 +171,7 @@ class DataDogLogger(
batch_size=_resolve_dd_batch_size(),
)
except Exception as e:
verbose_logger.exception(f"Datadog: Got exception on init Datadog client {e!s}")
verbose_logger.exception(f"Datadog: Got exception on init Datadog client {e}")
raise e
def _get_datadog_params(self) -> dict:
@ -257,7 +257,7 @@ class DataDogLogger(
await self._log_async_event(kwargs, response_obj, start_time, end_time)
except Exception as e:
verbose_logger.exception(f"Datadog Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Datadog Layer Error - {e}\n{traceback.format_exc()}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
try:
@ -265,7 +265,7 @@ class DataDogLogger(
await self._log_async_event(kwargs, response_obj, start_time, end_time)
except Exception as e:
verbose_logger.exception(f"Datadog Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Datadog Layer Error - {e}\n{traceback.format_exc()}")
async def async_post_call_failure_hook(
self,
@ -340,7 +340,7 @@ class DataDogLogger(
if len(self.log_queue) >= self.batch_size:
await self.flush_queue()
except Exception as e:
verbose_logger.exception(f"Datadog: async_post_call_failure_hook - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Datadog: async_post_call_failure_hook - {e}\n{traceback.format_exc()}")
return None
async def async_send_batch(self):
@ -380,7 +380,7 @@ class DataDogLogger(
except Exception as e:
self.log_queue = batch_to_send + self.log_queue
verbose_logger.exception(f"Datadog Error sending batch API - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Datadog Error sending batch API - {e}\n{traceback.format_exc()}")
async def _send_with_413_split(self, batch: list) -> list:
"""
@ -411,7 +411,7 @@ class DataDogLogger(
if isinstance(e, MaskedHTTPStatusError) and e.status_code == 413:
response = e.response
else:
verbose_logger.exception(f"Datadog Error sending batch API - {e!s}")
verbose_logger.exception(f"Datadog Error sending batch API - {e}")
return self._undelivered(chunk, pending)
if response.status_code == 413:
@ -515,7 +515,7 @@ class DataDogLogger(
)
except Exception as e:
verbose_logger.exception(f"Datadog Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Datadog Layer Error - {e}\n{traceback.format_exc()}")
async def _log_async_event(self, kwargs, response_obj, start_time, end_time):
dd_payload = self.create_datadog_logging_payload(

View file

@ -84,7 +84,7 @@ class DatadogCostManagementLogger(CustomBatchLogger):
await self.async_send_batch()
except Exception as e:
verbose_logger.exception(f"Datadog Cost Management: Error in async_log_success_event: {e!s}")
verbose_logger.exception(f"Datadog Cost Management: Error in async_log_success_event: {e}")
async def async_send_batch(self):
if not self.log_queue:
@ -104,7 +104,7 @@ class DatadogCostManagementLogger(CustomBatchLogger):
await self._upload_to_datadog(aggregated_entries)
except Exception as e:
self.log_queue = batch_to_send + self.log_queue
verbose_logger.exception(f"Datadog Cost Management: Error in async_send_batch: {e!s}")
verbose_logger.exception(f"Datadog Cost Management: Error in async_send_batch: {e}")
def _aggregate_costs(self, logs: list[StandardLoggingPayload]) -> list[DatadogFOCUSCostEntry]:
"""

View file

@ -89,7 +89,7 @@ class DataDogLLMObsLogger(CustomBatchLogger):
kwargs.update(dict_datadog_llm_obs_params)
CustomBatchLogger.__init__(self, **kwargs, flush_lock=self.flush_lock)
except Exception as e:
verbose_logger.exception(f"DataDogLLMObs: Error initializing - {e!s}")
verbose_logger.exception(f"DataDogLLMObs: Error initializing - {e}")
raise e
def _configure_dd_agent(self, dd_agent_host: str):
@ -145,7 +145,7 @@ class DataDogLLMObsLogger(CustomBatchLogger):
if len(self.log_queue) >= self.batch_size:
await self.async_send_batch()
except Exception as e:
verbose_logger.exception(f"DataDogLLMObs: Error logging success event - {e!s}")
verbose_logger.exception(f"DataDogLLMObs: Error logging success event - {e}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
try:
@ -157,7 +157,7 @@ class DataDogLLMObsLogger(CustomBatchLogger):
if len(self.log_queue) >= self.batch_size:
await self.async_send_batch()
except Exception as e:
verbose_logger.exception(f"DataDogLLMObs: Error logging failure event - {e!s}")
verbose_logger.exception(f"DataDogLLMObs: Error logging failure event - {e}")
async def async_send_batch(self):
try:
@ -214,7 +214,7 @@ class DataDogLLMObsLogger(CustomBatchLogger):
except httpx.HTTPStatusError as e:
verbose_logger.exception(f"DataDogLLMObs: Error sending batch - {e.response.text}")
except Exception as e:
verbose_logger.exception(f"DataDogLLMObs: Error sending batch - {e!s}")
verbose_logger.exception(f"DataDogLLMObs: Error sending batch - {e}")
def create_llm_obs_payload(self, kwargs: dict, start_time: datetime, end_time: datetime) -> LLMObsPayload:
standard_logging_payload: StandardLoggingPayload | None = kwargs.get("standard_logging_object")
@ -707,7 +707,7 @@ class DataDogLLMObsLogger(CustomBatchLogger):
kv_pairs[f"tool_calls.{idx}.function.arguments"] = json.dumps(function_arguments)
except (KeyError, TypeError, ValueError) as e:
verbose_logger.debug(f"DataDogLLMObs: Error processing tool call {idx}: {e!s}")
verbose_logger.debug(f"DataDogLLMObs: Error processing tool call {idx}: {e}")
continue
return kv_pairs
@ -747,6 +747,6 @@ class DataDogLLMObsLogger(CustomBatchLogger):
tool_call_metadata[f"output_{key}"] = value
except Exception as e:
verbose_logger.debug(f"DataDogLLMObs: Error extracting tool call metadata: {e!s}")
verbose_logger.debug(f"DataDogLLMObs: Error extracting tool call metadata: {e}")
return tool_call_metadata

View file

@ -180,7 +180,7 @@ class DatadogMetricsLogger(CustomBatchLogger):
await self.flush_queue()
except Exception as e:
verbose_logger.exception(f"Datadog Metrics: Error in async_log_success_event: {e!s}")
verbose_logger.exception(f"Datadog Metrics: Error in async_log_success_event: {e}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
try:
@ -202,7 +202,7 @@ class DatadogMetricsLogger(CustomBatchLogger):
await self.flush_queue()
except Exception as e:
verbose_logger.exception(f"Datadog Metrics: Error in async_log_failure_event: {e!s}")
verbose_logger.exception(f"Datadog Metrics: Error in async_log_failure_event: {e}")
async def async_send_batch(self):
if not self.log_queue:
@ -214,7 +214,7 @@ class DatadogMetricsLogger(CustomBatchLogger):
try:
await self._upload_to_datadog(payload_data)
except Exception as e:
verbose_logger.exception(f"Datadog Metrics: Error in async_send_batch: {e!s}")
verbose_logger.exception(f"Datadog Metrics: Error in async_send_batch: {e}")
raise
async def _upload_to_datadog(self, payload: DatadogMetricsPayload):

View file

@ -70,7 +70,7 @@ class DyanmoDBLogger:
# Assuming log_data is a dictionary with log information
response = table.put_item(Item=payload)
print_verbose(f"Response from DynamoDB:{response!s}")
print_verbose(f"Response from DynamoDB:{response}")
print_verbose(f"DynamoDB Layer Logging - final response object: {response_obj}")
return response

View file

@ -128,7 +128,7 @@ class GalileoObserve(CustomLogger):
except Exception as e:
return IntegrationHealthCheckStatus(
status="unhealthy",
error_message=f"Galileo health check failed: {e!s}",
error_message=f"Galileo health check failed: {e}",
)
async def async_set_galileo_headers(self) -> None:

View file

@ -76,7 +76,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils):
await self.log_queue.put(GCSLogQueueItem(payload=logging_payload, kwargs=kwargs, response_obj=response_obj))
except Exception as e:
verbose_logger.exception(f"GCS Bucket logging error: {e!s}")
verbose_logger.exception(f"GCS Bucket logging error: {e}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
try:
@ -95,7 +95,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils):
await self.log_queue.put(GCSLogQueueItem(payload=logging_payload, kwargs=kwargs, response_obj=response_obj))
except Exception as e:
verbose_logger.exception(f"GCS Bucket logging error: {e!s}")
verbose_logger.exception(f"GCS Bucket logging error: {e}")
def _drain_queue_batch(self) -> list[GCSLogQueueItem]:
"""
@ -218,7 +218,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils):
except Exception as e:
success_count = 0
error_count = len(items)
verbose_logger.exception(f"GCS Bucket error logging batch payload to GCS bucket: {e!s}")
verbose_logger.exception(f"GCS Bucket error logging batch payload to GCS bucket: {e}")
return (success_count, error_count)
async def _send_individual_logs(self, items: list[GCSLogQueueItem]) -> None:
@ -255,7 +255,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils):
logging_payload=item["payload"],
)
except Exception as e:
verbose_logger.exception(f"GCS Bucket error logging individual payload to GCS bucket: {e!s}")
verbose_logger.exception(f"GCS Bucket error logging individual payload to GCS bucket: {e}")
async def async_send_batch(self):
"""
@ -336,7 +336,7 @@ class GCSBucketLogger(GCSBucketBase, AdditionalLoggingUtils):
loaded_response = json.loads(response)
return loaded_response
except Exception as e:
verbose_logger.debug(f"Failed to fetch payload for date {date_str}: {e!s}")
verbose_logger.debug(f"Failed to fetch payload for date {date_str}: {e}")
continue
return None

View file

@ -132,7 +132,7 @@ class GcsPubSubLogger(CustomBatchLogger):
await self.async_send_batch()
except Exception as e:
verbose_logger.exception(f"PubSub Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"PubSub Layer Error - {e}\n{traceback.format_exc()}")
async def async_send_batch(self):
"""
@ -148,7 +148,7 @@ class GcsPubSubLogger(CustomBatchLogger):
await self.publish_message(message)
except Exception as e:
verbose_logger.exception(f"PubSub Error sending batch - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"PubSub Error sending batch - {e}\n{traceback.format_exc()}")
finally:
self.log_queue.clear()

View file

@ -42,7 +42,7 @@ def load_compatible_callbacks() -> dict:
with open(json_path, "r") as f:
return json.load(f)
except Exception as e:
verbose_logger.warning(f"Error loading generic_api_compatible_callbacks.json: {e!s}")
verbose_logger.warning(f"Error loading generic_api_compatible_callbacks.json: {e}")
return {}
@ -214,7 +214,7 @@ class GenericAPILogger(CustomBatchLogger):
key, value = item.split("=", 1)
headers_dict[key.strip()] = value.strip()
except Exception as e:
verbose_logger.warning(f"Error parsing headers from environment variables: {e!s}")
verbose_logger.warning(f"Error parsing headers from environment variables: {e}")
# 2. Update with litellm generic headers if available
if litellm.generic_logger_headers:
@ -308,7 +308,7 @@ class GenericAPILogger(CustomBatchLogger):
await self.async_send_batch()
except Exception as e:
verbose_logger.exception(f"Generic API Logger Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Generic API Logger Error - {e}\n{traceback.format_exc()}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
"""
@ -339,7 +339,7 @@ class GenericAPILogger(CustomBatchLogger):
await self.async_send_batch()
except Exception as e:
verbose_logger.exception(f"Generic API Logger Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Generic API Logger Error - {e}\n{traceback.format_exc()}")
async def async_send_batch(self):
"""
@ -395,7 +395,7 @@ class GenericAPILogger(CustomBatchLogger):
)
except Exception as e:
verbose_logger.exception(f"Generic API Logger Error sending batch - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Generic API Logger Error sending batch - {e}\n{traceback.format_exc()}")
finally:
self.log_queue.clear()

View file

@ -330,7 +330,7 @@ class LangFuseLogger:
return {"trace_id": trace_id, "generation_id": generation_id}
except Exception as e:
verbose_logger.exception(f"Langfuse Layer Error(): Exception occured - {e!s}")
verbose_logger.exception(f"Langfuse Layer Error(): Exception occured - {e}")
return {"trace_id": None, "generation_id": None}
def _get_langfuse_input_output_content(

View file

@ -317,7 +317,7 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge
except Exception as e:
from litellm._logging import verbose_logger
verbose_logger.exception(f"Langfuse Layer Error - Exception occurred while logging success event: {e!s}")
verbose_logger.exception(f"Langfuse Layer Error - Exception occurred while logging success event: {e}")
self.handle_callback_failure(callback_name="langfuse")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
@ -347,5 +347,5 @@ class LangfusePromptManagement(LangFuseLogger, PromptManagementBase, CustomLogge
except Exception as e:
from litellm._logging import verbose_logger
verbose_logger.exception(f"Langfuse Layer Error - Exception occurred while logging failure event: {e!s}")
verbose_logger.exception(f"Langfuse Layer Error - Exception occurred while logging failure event: {e}")
self.handle_callback_failure(callback_name="langfuse")

View file

@ -35,7 +35,7 @@ class LogfireLogger:
if logfire.DEFAULT_LOGFIRE_INSTANCE.config.send_to_logfire:
logfire.configure(token=os.getenv("LOGFIRE_TOKEN"))
except Exception as e:
print_verbose(f"Got exception on init logfire client {e!s}")
print_verbose(f"Got exception on init logfire client {e}")
raise e
def _get_span_config(self, payload) -> SpanConfig:
@ -159,4 +159,4 @@ class LogfireLogger:
print_verbose(f"Logfire Layer Logging - final response object: {response_obj}")
except Exception as e:
verbose_logger.debug(f"Logfire Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.debug(f"Logfire Layer Error - {e}\n{traceback.format_exc()}")

View file

@ -81,7 +81,7 @@ class OpikLogger(CustomBatchLogger):
self.flush_lock: asyncio.Lock | None = asyncio.Lock()
except Exception as e:
verbose_logger.exception(
f"OpikLogger - Asynchronous processing not initialized as we are not running in an async context {e!s}"
f"OpikLogger - Asynchronous processing not initialized as we are not running in an async context {e}"
)
self.flush_lock = None
@ -161,7 +161,7 @@ class OpikLogger(CustomBatchLogger):
verbose_logger.debug("OpikLogger - Flushing batch")
await self.flush_queue()
except Exception as e:
verbose_logger.exception(f"OpikLogger failed to log success event - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"OpikLogger failed to log success event - {e}\n{traceback.format_exc()}")
def _sync_send(self, url: str, headers: dict[str, str], batch: dict[str, Any]) -> None:
try:
@ -174,7 +174,7 @@ class OpikLogger(CustomBatchLogger):
if response.status_code != 204:
raise Exception(f"Response from opik API status_code: {response.status_code}, text: {response.text}")
except Exception as e:
verbose_logger.exception(f"OpikLogger failed to send batch - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"OpikLogger failed to send batch - {e}\n{traceback.format_exc()}")
def log_success_event(
self,
@ -245,7 +245,7 @@ class OpikLogger(CustomBatchLogger):
batch={"spans": [span_payload.__dict__]},
)
except Exception as e:
verbose_logger.exception(f"OpikLogger failed to log success event - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"OpikLogger failed to log success event - {e}\n{traceback.format_exc()}")
async def _submit_batch(self, url: str, headers: dict[str, str], batch: dict[str, Any]) -> None:
try:
@ -261,7 +261,7 @@ class OpikLogger(CustomBatchLogger):
else:
verbose_logger.info(f"OpikLogger - {len(self.log_queue)} Opik events submitted")
except Exception as e:
verbose_logger.exception(f"OpikLogger failed to send batch - {e!s}")
verbose_logger.exception(f"OpikLogger failed to send batch - {e}")
def _create_opik_headers(self) -> dict[str, str]:
headers: dict[str, str] = {}

View file

@ -72,7 +72,7 @@ class PostHogLogger(CustomBatchLogger):
super().__init__(**kwargs, flush_lock=None, batch_size=POSTHOG_MAX_BATCH_SIZE)
except Exception as e:
verbose_logger.exception(f"PostHog: Got exception on init PostHog client {e!s}")
verbose_logger.exception(f"PostHog: Got exception on init PostHog client {e}")
raise e
def log_success_event(self, kwargs, response_obj, start_time, end_time):
@ -107,7 +107,7 @@ class PostHogLogger(CustomBatchLogger):
verbose_logger.debug("PostHog: Sync event successfully sent")
except Exception as e:
verbose_logger.exception(f"PostHog Sync Layer Error - {e!s}")
verbose_logger.exception(f"PostHog Sync Layer Error - {e}")
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
try:
@ -115,7 +115,7 @@ class PostHogLogger(CustomBatchLogger):
self._ensure_async_setup() # Lazy initialization
await self._log_async_event(kwargs, response_obj, start_time, end_time)
except Exception as e:
verbose_logger.exception(f"PostHog Layer Error - {e!s}")
verbose_logger.exception(f"PostHog Layer Error - {e}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
try:
@ -123,7 +123,7 @@ class PostHogLogger(CustomBatchLogger):
self._ensure_async_setup() # Lazy initialization
await self._log_async_event(kwargs, response_obj, start_time, end_time)
except Exception as e:
verbose_logger.exception(f"PostHog Layer Error - {e!s}")
verbose_logger.exception(f"PostHog Layer Error - {e}")
async def _log_async_event(self, kwargs, response_obj=None, start_time=0.0, end_time=0.0):
# Note: response_obj, start_time, end_time not used - all data comes from kwargs
@ -367,7 +367,7 @@ class PostHogLogger(CustomBatchLogger):
else:
verbose_logger.debug(f"PostHog: Batch of {len(self.log_queue)} events successfully sent")
except Exception as e:
verbose_logger.exception(f"PostHog Error sending batch API - {e!s}")
verbose_logger.exception(f"PostHog Error sending batch API - {e}")
def _ensure_async_setup(self):
if not self._async_initialized:
@ -377,7 +377,7 @@ class PostHogLogger(CustomBatchLogger):
self._async_initialized = True
verbose_logger.debug("PostHog: Async components initialized")
except Exception as e:
verbose_logger.error(f"PostHog: Failed to initialize async components: {e!s}")
verbose_logger.error(f"PostHog: Failed to initialize async components: {e}")
raise
def _extract_metadata(self, kwargs: dict[str, Any]) -> dict[str, Any]:
@ -445,4 +445,4 @@ class PostHogLogger(CustomBatchLogger):
self.log_queue.clear()
except Exception as e:
verbose_logger.error(f"PostHog: Error flushing events on exit: {e!s}")
verbose_logger.error(f"PostHog: Error flushing events on exit: {e}")

View file

@ -683,7 +683,7 @@ class PrometheusLogger(CustomLogger):
)
except Exception as e:
print_verbose(f"Got exception on init prometheus client {e!s}")
print_verbose(f"Got exception on init prometheus client {e}")
raise e
def _parse_prometheus_config(self) -> dict[str, list[str]]:
@ -2132,7 +2132,7 @@ class PrometheusLogger(CustomLogger):
response_cost=0,
)
except Exception as e:
verbose_logger.exception(f"prometheus Layer Error(): Exception occured - {e!s}")
verbose_logger.exception(f"prometheus Layer Error(): Exception occured - {e}")
def _extract_status_code(
self,
@ -2383,7 +2383,7 @@ class PrometheusLogger(CustomLogger):
)
except Exception as e:
verbose_logger.exception(f"prometheus Layer Error(): Exception occured - {e!s}")
verbose_logger.exception(f"prometheus Layer Error(): Exception occured - {e}")
async def async_post_call_success_hook(self, data: dict, user_api_key_dict: UserAPIKeyAuth, response):
"""
@ -2608,7 +2608,7 @@ class PrometheusLogger(CustomLogger):
)
except Exception as e:
verbose_logger.debug(f"Prometheus Error: set_llm_deployment_failure_metrics. Exception occured - {e!s}")
verbose_logger.debug(f"Prometheus Error: set_llm_deployment_failure_metrics. Exception occured - {e}")
def _set_deployment_tpm_rpm_limit_metrics(
self,
@ -2722,9 +2722,7 @@ class PrometheusLogger(CustomLogger):
)
self.litellm_remaining_requests_metric.labels(**_labels).set(remaining_requests)
except Exception as e:
verbose_logger.exception(
f"Prometheus Error: _async_set_router_remaining_metrics. Exception occured - {e!s}"
)
verbose_logger.exception(f"Prometheus Error: _async_set_router_remaining_metrics. Exception occured - {e}")
def set_llm_deployment_success_metrics(
self,
@ -2867,7 +2865,7 @@ class PrometheusLogger(CustomLogger):
self.litellm_deployment_latency_per_output_token.labels(**_labels).observe(latency_per_token)
except Exception as e:
verbose_logger.exception(f"Prometheus Error: set_llm_deployment_success_metrics. Exception occured - {e!s}")
verbose_logger.exception(f"Prometheus Error: set_llm_deployment_success_metrics. Exception occured - {e}")
return
def _record_guardrail_metrics(
@ -2912,7 +2910,7 @@ class PrometheusLogger(CustomLogger):
hook_type=hook_type,
).inc()
except Exception as e:
verbose_logger.debug(f"Error recording guardrail metrics: {e!s}")
verbose_logger.debug(f"Error recording guardrail metrics: {e}")
########################################
# Managed Batch Metric Recording Methods
@ -3315,7 +3313,7 @@ class PrometheusLogger(CustomLogger):
await set_metrics_function(data)
except Exception as e:
verbose_logger.exception(f"Error initializing {data_type} budget metrics: {e!s}")
verbose_logger.exception(f"Error initializing {data_type} budget metrics: {e}")
async def _initialize_team_budget_metrics(self):
"""
@ -3506,7 +3504,7 @@ class PrometheusLogger(CustomLogger):
self.litellm_teams_count_metric.set(total_teams)
verbose_logger.debug(f"Prometheus: set litellm_teams_count to {total_teams}")
except Exception as e:
verbose_logger.exception(f"Error initializing user/team count metrics: {e!s}")
verbose_logger.exception(f"Error initializing user/team count metrics: {e}")
async def _set_key_list_budget_metrics(self, keys: list[str | UserAPIKeyAuth]):
"""Helper function to set budget metrics for a list of keys"""
@ -3597,7 +3595,7 @@ class PrometheusLogger(CustomLogger):
user_api_key_cache=user_api_key_cache,
)
except Exception as e:
verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting team info: {e!s}")
verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting team info: {e}")
return team_object
if team_info:
@ -3695,7 +3693,7 @@ class PrometheusLogger(CustomLogger):
include_budget_table=True,
)
except Exception as e:
verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting org info: {e!s}")
verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting org info: {e}")
return
if org_info is None:
@ -3852,7 +3850,7 @@ class PrometheusLogger(CustomLogger):
if key_object:
user_api_key_dict.budget_reset_at = key_object.budget_reset_at
except Exception as e:
verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting key info: {e!s}")
verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting key info: {e}")
return user_api_key_dict
@ -3917,7 +3915,7 @@ class PrometheusLogger(CustomLogger):
check_db_only=False,
)
except Exception as e:
verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting user info: {e!s}")
verbose_logger.debug(f"[Non-Blocking] Prometheus: Error getting user info: {e}")
return user_object
if user_info:

View file

@ -82,7 +82,7 @@ class PrometheusServicesLogger:
self.mock_testing_failure_calls = 0
except Exception as e:
print_verbose(f"Got exception on init prometheus client {e!s}")
print_verbose(f"Got exception on init prometheus client {e}")
raise e
def _get_service_metrics_initialize(self, service: ServiceTypes) -> list[ServiceMetrics]:

File diff suppressed because it is too large Load diff

View file

@ -78,7 +78,7 @@ class S3Logger:
**kwargs,
)
except Exception as e:
print_verbose(f"Got exception on init s3 client {e!s}")
print_verbose(f"Got exception on init s3 client {e}")
raise e
async def _async_log_event(self, kwargs, response_obj, start_time, end_time, print_verbose):
@ -163,12 +163,12 @@ class S3Logger:
**sse_params,
)
print_verbose(f"Response from s3:{response!s}")
print_verbose(f"Response from s3:{response}")
print_verbose(f"s3 Layer Logging - final response object: {response_obj}")
return response
except Exception as e:
verbose_logger.exception(f"s3 Layer Error - {e!s}")
verbose_logger.exception(f"s3 Layer Error - {e}")
def _validated_sse_value(name: str, value: str | None) -> str | None:

View file

@ -125,7 +125,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM):
BaseAWSLLM.__init__(self)
except Exception as e:
print_verbose(f"Got exception on init s3 client {e!s}")
print_verbose(f"Got exception on init s3 client {e}")
raise e
def _init_s3_params(
@ -284,7 +284,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM):
self.batch_size,
)
except Exception as e:
verbose_logger.exception(f"s3 Layer Error - {e!s}")
verbose_logger.exception(f"s3 Layer Error - {e}")
self.handle_callback_failure(callback_name="S3Logger")
async def async_upload_data_to_s3(self, batch_logging_element: s3BatchLoggingElement):
@ -383,7 +383,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM):
response.raise_for_status()
break
except Exception as e:
verbose_logger.exception(f"Error uploading to s3: {e!s}")
verbose_logger.exception(f"Error uploading to s3: {e}")
self.handle_callback_failure(callback_name="S3Logger")
async def async_send_batch(self):
@ -557,7 +557,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM):
response.raise_for_status()
break
except Exception as e:
verbose_logger.exception(f"Error uploading to s3: {e!s}")
verbose_logger.exception(f"Error uploading to s3: {e}")
self.handle_callback_failure(callback_name="S3Logger")
async def _download_object_from_s3(self, s3_object_key: str) -> dict | None:
@ -642,7 +642,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM):
return response.json()
except Exception as e:
verbose_logger.exception(f"Error downloading from S3: {e!s}")
verbose_logger.exception(f"Error downloading from S3: {e}")
return None
async def get_proxy_server_request_from_cold_storage_with_object_key(
@ -666,5 +666,5 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM):
downloaded_object = await self._download_object_from_s3(object_key)
return downloaded_object
except Exception as e:
verbose_logger.exception(f"Error retrieving object {object_key} from cold storage: {e!s}")
verbose_logger.exception(f"Error retrieving object {object_key} from cold storage: {e}")
return None

View file

@ -113,7 +113,7 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM):
BaseAWSLLM.__init__(self)
except Exception as e:
print_verbose(f"Got exception on init sqs client {e!s}")
print_verbose(f"Got exception on init sqs client {e}")
raise e
def _init_sqs_params(
@ -215,7 +215,7 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM):
self.batch_size,
)
except Exception as e:
verbose_logger.exception(f"sqs Layer Error - {e!s}")
verbose_logger.exception(f"sqs Layer Error - {e}")
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
try:
@ -233,7 +233,7 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM):
)
except Exception as e:
verbose_logger.exception(f"Datadog Layer Error - {e!s}\n{traceback.format_exc()}")
verbose_logger.exception(f"Datadog Layer Error - {e}\n{traceback.format_exc()}")
async def async_send_batch(self) -> None:
verbose_logger.debug(f"sqs logger - sending batch of {len(self.log_queue)}")
@ -305,7 +305,7 @@ class SQSLogger(CustomBatchLogger, BaseAWSLLM):
)
response.raise_for_status()
except Exception as e:
verbose_logger.exception(f"Error sending to SQS: {e!s}")
verbose_logger.exception(f"Error sending to SQS: {e}")
async def async_health_check(self) -> IntegrationHealthCheckStatus:
"""

View file

@ -146,7 +146,7 @@ class VectorStorePreCallHook(CustomLogger):
return model, modified_messages, non_default_params
except Exception as e:
verbose_logger.exception(f"Error in VectorStorePreCallHook: {e!s}")
verbose_logger.exception(f"Error in VectorStorePreCallHook: {e}")
# Return original parameters on error
return model, messages, non_default_params
@ -275,7 +275,7 @@ class VectorStorePreCallHook(CustomLogger):
return response
except Exception as e:
verbose_logger.exception(f"Error adding search results to response: {e!s}")
verbose_logger.exception(f"Error adding search results to response: {e}")
# Don't fail the request if search results fail to be added
return None
@ -322,6 +322,6 @@ class VectorStorePreCallHook(CustomLogger):
return response_chunk
except Exception as e:
verbose_logger.exception(f"Error adding search results to streaming chunk: {e!s}")
verbose_logger.exception(f"Error adding search results to streaming chunk: {e}")
# Don't fail the request if search results fail to be added
return response_chunk

View file

@ -224,7 +224,7 @@ class WebSearchInterceptionLogger(CustomLogger):
content.append({"type": "text", "text": search_result_text})
response: dict[str, object] = {
"id": f"msg_{uuid.uuid4()!s}",
"id": f"msg_{uuid.uuid4()}",
"type": "message",
"role": "assistant",
"model": model,
@ -1038,8 +1038,8 @@ class WebSearchInterceptionLogger(CustomLogger):
@staticmethod
def _extract_search_text(result: object) -> str:
if isinstance(result, Exception):
verbose_logger.error(f"WebSearchInterception: Responses search failed with error: {result!s}")
return f"Search failed: {result!s}"
verbose_logger.error(f"WebSearchInterception: Responses search failed with error: {result}")
return f"Search failed: {result}"
if isinstance(result, tuple) and len(result) == 2:
text_value, _ = result
return text_value if isinstance(text_value, str) else str(text_value)
@ -1194,8 +1194,8 @@ class WebSearchInterceptionLogger(CustomLogger):
structured_results: list[SearchResponse | None] = []
for i, result in enumerate(search_results):
if isinstance(result, Exception):
verbose_logger.error(f"WebSearchInterception: Search {i} failed with error: {result!s}")
final_search_results.append(f"Search failed: {result!s}")
verbose_logger.error(f"WebSearchInterception: Search {i} failed with error: {result}")
final_search_results.append(f"Search failed: {result}")
structured_results.append(None)
elif isinstance(result, tuple) and len(result) == 2:
text_value, structured_value = result
@ -1308,7 +1308,7 @@ class WebSearchInterceptionLogger(CustomLogger):
)
return search_result_text, result
except Exception as e:
verbose_logger.error(f"WebSearchInterception: Search failed for '{query}': {e!s}")
verbose_logger.error(f"WebSearchInterception: Search failed for '{query}': {e}")
raise
async def _authorize_search_tool(
@ -1486,8 +1486,8 @@ class WebSearchInterceptionLogger(CustomLogger):
final_search_results: list[str] = []
for i, result in enumerate(search_results):
if isinstance(result, Exception):
verbose_logger.error(f"WebSearchInterception: Search {i} failed with error: {result!s}")
final_search_results.append(f"Search failed: {result!s}")
verbose_logger.error(f"WebSearchInterception: Search {i} failed with error: {result}")
final_search_results.append(f"Search failed: {result}")
elif isinstance(result, tuple) and len(result) == 2:
text_value, _ = result
final_search_results.append(cast(str, text_value) if isinstance(text_value, str) else str(text_value))

View file

@ -679,7 +679,7 @@ def _map_replicate_exception(
)
raise APIError(
status_code=500,
message=f"ReplicateException - {original_exception!s}",
message=f"ReplicateException - {original_exception}",
llm_provider="replicate",
model=model,
request=httpx.Request(
@ -2459,7 +2459,7 @@ def exception_type( # type: ignore
): # deal with edge-case invalid request error bug in openai-python sdk
exception_mapping_worked = True
raise BadRequestError(
message=f"{exception_provider} BadRequestError : This can happen due to missing AZURE_API_VERSION: {original_exception!s}",
message=f"{exception_provider} BadRequestError : This can happen due to missing AZURE_API_VERSION: {original_exception}",
model=model,
llm_provider=custom_llm_provider,
response=getattr(original_exception, "response", None),
@ -2478,7 +2478,7 @@ def exception_type( # type: ignore
)
else:
raise APIConnectionError(
message=f"{original_exception!s}\n{_redact_string(traceback.format_exc())}",
message=f"{original_exception}\n{_redact_string(traceback.format_exc())}",
llm_provider=custom_llm_provider,
model=model,
request=httpx.Request(method="POST", url="https://api.openai.com/v1/"), # stub the request

View file

@ -70,7 +70,7 @@ async def async_completion_with_fallbacks(**kwargs):
)
except Exception as e:
verbose_logger.exception(f"Fallback attempt failed for model {model}: {e!s}")
verbose_logger.exception(f"Fallback attempt failed for model {model}: {e}")
most_recent_exception_str = str(e)
continue

View file

@ -501,9 +501,9 @@ def get_llm_provider(
if isinstance(e, litellm.exceptions.BadRequestError):
raise e
else:
error_str = f"GetLLMProvider Exception - {e!s}\n\noriginal model: {model}"
error_str = f"GetLLMProvider Exception - {e}\n\noriginal model: {model}"
raise litellm.exceptions.BadRequestError( # type: ignore
message=f"GetLLMProvider Exception - {e!s}\n\noriginal model: {model}",
message=f"GetLLMProvider Exception - {e}\n\noriginal model: {model}",
model=model,
response=None,
llm_provider="",

View file

@ -292,7 +292,7 @@ def get_model_cost_map(url: str) -> dict:
str(e),
)
_cost_map_source_info.source = "local"
_cost_map_source_info.fallback_reason = f"Remote fetch failed: {e!s}"
_cost_map_source_info.fallback_reason = f"Remote fetch failed: {e}"
return _finalize_model_cost_map(GetModelCostMap.load_local_model_cost_map())
# Validate using cached count (cheap int comparison, no file I/O)

View file

@ -1,7 +1,7 @@
from collections.abc import Iterator
from collections.abc import Iterator, Mapping
from typing import Any
from litellm.types.utils import StandardCallbackDynamicParams
from litellm.types.utils import TRUSTED_CALLBACK_VARS_FIELD, StandardCallbackDynamicParams
_CLIENT_CALLBACK_METADATA_SLOTS: tuple[str, ...] = ("litellm_metadata", "metadata")
@ -75,14 +75,32 @@ _supported_callback_params = [
"turn_off_message_logging",
]
_request_blocked_callback_params = {
"gcs_bucket_name",
"gcs_path_service_account",
"dd_api_key",
"dd_site",
"dd_agent_host",
"dd_agent_port",
}
_request_blocked_callback_params = frozenset(
{
"gcs_bucket_name",
"gcs_path_service_account",
"dd_api_key",
"dd_site",
"dd_agent_host",
"dd_agent_port",
}
)
def get_trusted_callback_params(kwargs: Mapping[str, Any] | None) -> tuple[tuple[str, str], ...]:
"""
Read callback params the proxy itself stamped from admin-configured team/key callback settings.
Request-body values never reach this field: the proxy strips it from client input before
setting it, so callbacks can consume credentials and destinations here without re-validating.
Returned as pairs rather than a mapping because the caller keeps this on the Logging object,
which the proxy deep-copies; a mappingproxy is not copyable and a dict would be mutable.
"""
trusted_vars = kwargs.get(TRUSTED_CALLBACK_VARS_FIELD) if kwargs else None
if not isinstance(trusted_vars, Mapping):
return ()
return tuple((key, str(value)) for key, value in trusted_vars.items() if isinstance(key, str))
def initialize_standard_callback_dynamic_params(

View file

@ -166,6 +166,9 @@ from ..integrations.s3_v2 import S3Logger as S3V2Logger
from ..integrations.supabase import Supabase
from ..integrations.traceloop import TraceloopLogger
from .exception_mapping_utils import _get_response_headers
from .initialize_dynamic_callback_params import (
get_trusted_callback_params,
)
from .initialize_dynamic_callback_params import (
initialize_standard_callback_dynamic_params as _initialize_standard_callback_dynamic_params,
)
@ -199,7 +202,7 @@ try:
EnterpriseStandardLoggingPayloadSetup
)
except Exception as e:
verbose_logger.debug(f"[Non-Blocking] Unable to import GenericAPILogger - LiteLLM Enterprise Feature - {e!s}")
verbose_logger.debug(f"[Non-Blocking] Unable to import GenericAPILogger - LiteLLM Enterprise Feature - {e}")
GenericAPILogger = CustomLogger # type: ignore
ResendEmailLogger = CustomLogger # type: ignore
SendGridEmailLogger = CustomLogger # type: ignore
@ -362,6 +365,7 @@ class Logging(LiteLLMLoggingBaseClass):
self.standard_callback_dynamic_params: StandardCallbackDynamicParams = (
self.initialize_standard_callback_dynamic_params(kwargs)
)
self._trusted_callback_vars: tuple[tuple[str, str], ...] = get_trusted_callback_params(kwargs)
# Process dynamic callbacks (after standard_callback_dynamic_params is initialized,
# so team-scoped credentials are available for callback initialization)
@ -459,9 +463,10 @@ class Logging(LiteLLMLoggingBaseClass):
# pass only the relevant dynamic params as custom_logger_init_args.
_custom_logger_init_args: dict | None = None
if callback == "datadog":
_custom_logger_init_args = {
k: v for k, v in self.standard_callback_dynamic_params.items() if k.startswith("dd_")
}
# dd_* params are blocked from standard_callback_dynamic_params
# (request-level security); only the proxy-stamped team/key
# callback vars are admin-configured and trusted.
_custom_logger_init_args = {k: v for k, v in self._trusted_callback_vars if k.startswith("dd_")}
callback_class = _init_custom_logger_compatible_class(
callback, # type: ignore[arg-type]
@ -968,7 +973,7 @@ class Logging(LiteLLMLoggingBaseClass):
error=str(e),
)
_metadata["raw_request"] = f"Unable to Log \
raw request: {e!s}"
raw request: {e}"
if getattr(self, "logger_fn", None) and callable(self.logger_fn):
try:
self.logger_fn(
@ -976,7 +981,7 @@ class Logging(LiteLLMLoggingBaseClass):
) # Expectation: any logger function passed in by the user should accept a dict object
except Exception as e:
verbose_logger.exception(
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e!s}"
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}"
)
self.model_call_details["api_call_start_time"] = datetime.datetime.now()
@ -1036,14 +1041,14 @@ class Logging(LiteLLMLoggingBaseClass):
callback_func=callback,
)
except Exception as e:
verbose_logger.exception(f"litellm.Logging.pre_call(): Exception occured - {e!s}")
verbose_logger.exception(f"litellm.Logging.pre_call(): Exception occured - {e}")
verbose_logger.debug(
f"LiteLLM.Logging: is sentry capture exception initialized {capture_exception}"
)
if capture_exception: # log this error to sentry for debugging
capture_exception(e)
except Exception as e:
verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e!s}")
verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}")
verbose_logger.error(f"LiteLLM.Logging: is sentry capture exception initialized {capture_exception}")
if capture_exception: # log this error to sentry for debugging
capture_exception(e)
@ -1159,7 +1164,7 @@ class Logging(LiteLLMLoggingBaseClass):
) # Expectation: any logger function passed in by the user should accept a dict object
except Exception as e:
verbose_logger.exception(
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e!s}"
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}"
)
original_response = redact_message_input_output_from_logging(
model_call_details=(self.model_call_details if hasattr(self, "model_call_details") else {}),
@ -1196,7 +1201,7 @@ class Logging(LiteLLMLoggingBaseClass):
)
except Exception as e:
verbose_logger.exception(
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while post-call logging with integrations {e!s}"
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while post-call logging with integrations {e}"
)
verbose_logger.debug(
f"LiteLLM.Logging: is sentry capture exception initialized {capture_exception}"
@ -1204,7 +1209,7 @@ class Logging(LiteLLMLoggingBaseClass):
if capture_exception: # log this error to sentry for debugging
capture_exception(e)
except Exception as e:
verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e!s}")
verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}")
async def async_post_mcp_tool_call_hook(
self,
@ -1244,7 +1249,7 @@ class Logging(LiteLLMLoggingBaseClass):
if response is not None:
response_obj = self._parse_post_mcp_call_hook_response(response=response)
except Exception as e:
verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e!s}")
verbose_logger.exception(f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while logging {e}")
return response_obj
def _parse_post_mcp_call_hook_response(self, response: MCPPostCallResponseObject | None) -> Any:
@ -1889,7 +1894,7 @@ class Logging(LiteLLMLoggingBaseClass):
return start_time, end_time, result
except Exception as e:
raise Exception(f"[Non-Blocking] LiteLLM.Success_Call Error: {e!s}")
raise Exception(f"[Non-Blocking] LiteLLM.Success_Call Error: {e}")
def _is_recognized_call_type_for_logging(
self,
@ -2378,7 +2383,7 @@ class Logging(LiteLLMLoggingBaseClass):
pass
except Exception as e:
verbose_logger.exception(
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while success logging {e!s}",
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while success logging {e}",
)
async def async_success_handler(self, result=None, start_time=None, end_time=None, cache_hit=None, **kwargs):
@ -2694,7 +2699,7 @@ class Logging(LiteLLMLoggingBaseClass):
break # Only increment once
except Exception as e:
verbose_logger.debug(f"Error in _handle_callback_failure: {e!s}")
verbose_logger.debug(f"Error in _handle_callback_failure: {e}")
def _failure_handler_helper_fn(self, exception, traceback_exception, start_time=None, end_time=None):
if start_time is None:
@ -2931,14 +2936,14 @@ class Logging(LiteLLMLoggingBaseClass):
except Exception as e:
print_verbose(
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure logging with integrations {e!s}"
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure logging with integrations {e}"
)
print_verbose(f"LiteLLM.Logging: is sentry capture exception initialized {capture_exception}")
if capture_exception: # log this error to sentry for debugging
capture_exception(e)
except Exception as e:
verbose_logger.exception(
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure logging {e!s}"
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure logging {e}"
)
async def async_failure_handler(self, exception, traceback_exception, start_time=None, end_time=None):
@ -2995,7 +3000,7 @@ class Logging(LiteLLMLoggingBaseClass):
except Exception as e:
verbose_logger.exception(
f"LiteLLM.LoggingError: [Non-Blocking] Exception occurred while failure \
logging {e!s}\nCallback={callback}"
logging {e}\nCallback={callback}"
)
# Track callback logging failures in Prometheus
self._handle_callback_failure(callback=callback)
@ -5426,7 +5431,7 @@ def get_standard_logging_object_payload(
return payload
except Exception as e:
verbose_logger.exception(f"Error creating standard logging object - {e!s}")
verbose_logger.exception(f"Error creating standard logging object - {e}")
return None

View file

@ -150,7 +150,7 @@ def _generic_cost_per_character(
prompt_cost = prompt_characters * custom_prompt_cost
except Exception as e:
verbose_logger.exception(
f"litellm.litellm_core_utils.llm_cost_calc.utils.py::cost_per_character(): Exception occured - {e!s}\nDefaulting to None"
f"litellm.litellm_core_utils.llm_cost_calc.utils.py::cost_per_character(): Exception occured - {e}\nDefaulting to None"
)
prompt_cost = None
@ -165,7 +165,7 @@ def _generic_cost_per_character(
completion_cost = completion_characters * custom_completion_cost
except Exception as e:
verbose_logger.exception(
f"litellm.litellm_core_utils.llm_cost_calc.utils.py::cost_per_character(): Exception occured - {e!s}\nDefaulting to None"
f"litellm.litellm_core_utils.llm_cost_calc.utils.py::cost_per_character(): Exception occured - {e}\nDefaulting to None"
)
completion_cost = None

View file

@ -53,7 +53,7 @@ def get_api_base(model: str, optional_params: dict | LiteLLM_Params) -> str | No
api_key=_optional_params.api_key,
)
except Exception as e:
verbose_logger.debug(f"Error occurred in getting api base - {e!s}")
verbose_logger.debug(f"Error occurred in getting api base - {e}")
custom_llm_provider = None
dynamic_api_base = None

View file

@ -178,7 +178,7 @@ def _get_parent_otel_span_from_logging_obj(
return _get_parent_otel_span_from_kwargs(logging_obj.model_call_details)
except Exception as e:
verbose_logger.exception(f"Error in _get_parent_otel_span_from_logging_obj: {e!s}")
verbose_logger.exception(f"Error in _get_parent_otel_span_from_logging_obj: {e}")
return None
@ -265,7 +265,7 @@ def _set_duration_in_model_call_details(
else:
verbose_logger.debug("`logging_obj` not found - unable to track `llm_api_duration_ms")
except Exception as e:
verbose_logger.warning(f"Error setting `llm_api_duration_ms`: {e!s}")
verbose_logger.warning(f"Error setting `llm_api_duration_ms`: {e}")
def track_llm_api_timing():
@ -321,7 +321,7 @@ def track_llm_api_timing():
)
)
except Exception as e:
verbose_logger.debug(f"Error in service logging: {e!s}")
verbose_logger.debug(f"Error in service logging: {e}")
@functools.wraps(func)
def sync_wrapper(*args, **kwargs):
@ -366,7 +366,7 @@ def track_llm_api_timing():
parent_otel_span=parent_otel_span,
)
except Exception as e:
verbose_logger.debug(f"Error in service logging: {e!s}")
verbose_logger.debug(f"Error in service logging: {e}")
# Check if the function is async or sync
if inspect.iscoroutinefunction(func):

View file

@ -1683,7 +1683,7 @@ def parse_tool_call_arguments(
if context:
error_parts.append(f"({context})")
error_message = " ".join(error_parts) + f". Error: {original_error!s}. Arguments: {arguments}"
error_message = " ".join(error_parts) + f". Error: {original_error}. Arguments: {arguments}"
raise ValueError(error_message) from original_error

View file

@ -438,9 +438,7 @@ def _render_chat_template(env, chat_template: str, bos_token: str, eos_token: st
return rendered_text
except Exception as e:
raise Exception(
f"Error rendering template - {e!s}"
) # don't use verbose_logger.exception, if exception is raised
raise Exception(f"Error rendering template - {e}") # don't use verbose_logger.exception, if exception is raised
async def _afetch_and_extract_template(
@ -858,7 +856,7 @@ def convert_to_anthropic_image_obj(openai_image_url: str, format: str | None) ->
raise
except Exception as e:
raise Exception(
f"""Image url not in expected format. Example Expected input - "image_url": "data:image/jpeg;base64,{{base64_image}}". Supported formats - ['image/jpeg', 'image/png', 'image/gif', 'image/webp']. Error: {e!s}"""
f"""Image url not in expected format. Example Expected input - "image_url": "data:image/jpeg;base64,{{base64_image}}". Supported formats - ['image/jpeg', 'image/png', 'image/gif', 'image/webp']. Error: {e}"""
)
@ -1361,7 +1359,7 @@ def convert_to_gemini_tool_call_invoke(
)
return _parts_list
except Exception as e:
raise Exception(f"Unable to convert openai tool calls={message} to gemini tool calls. Received error={e!s}")
raise Exception(f"Unable to convert openai tool calls={message} to gemini tool calls. Received error={e}")
def convert_to_gemini_tool_call_result(
@ -3713,7 +3711,7 @@ def _convert_to_bedrock_tool_call_invoke(
_parts_list.append(cache_point_block)
return _parts_list
except Exception as e:
raise Exception(f"Unable to convert openai tool calls={tool_calls} to bedrock tool calls. Received error={e!s}")
raise Exception(f"Unable to convert openai tool calls={tool_calls} to bedrock tool calls. Received error={e}")
def _append_bedrock_tool_result_media_block(

View file

@ -618,7 +618,7 @@ class CustomStreamWrapper:
else:
return ""
except Exception as e:
verbose_logger.exception(f"litellm.CustomStreamWrapper.handle_baseten_chunk(): Exception occured - {e!s}")
verbose_logger.exception(f"litellm.CustomStreamWrapper.handle_baseten_chunk(): Exception occured - {e}")
return ""
def handle_triton_stream(self, chunk):
@ -1179,7 +1179,7 @@ class CustomStreamWrapper:
content=None,
tool_calls=[
{
"id": f"call_{uuid.uuid4()!s}",
"id": f"call_{uuid.uuid4()}",
"function": {
"arguments": args_str,
"name": function_call.name,
@ -1204,7 +1204,7 @@ class CustomStreamWrapper:
)
except Exception:
if chunk.candidates[0].finish_reason.name == "SAFETY": # type: ignore
raise Exception(f"The response was blocked by VertexAI. {chunk!s}")
raise Exception(f"The response was blocked by VertexAI. {chunk}")
else:
completion_obj["content"] = str(chunk)
elif self.custom_llm_provider == "petals":
@ -1430,7 +1430,7 @@ class CustomStreamWrapper:
model_response.choices[0].delta = Delta(**_json_delta)
except Exception as e:
verbose_logger.exception(
f"litellm.CustomStreamWrapper.chunk_creator(): Exception occured - {e!s}"
f"litellm.CustomStreamWrapper.chunk_creator(): Exception occured - {e}"
)
model_response.choices[0].delta = Delta()
elif self._has_any_special_delta_attributes(delta):
@ -1538,7 +1538,7 @@ class CustomStreamWrapper:
except Exception as e:
from litellm._logging import verbose_logger
verbose_logger.exception(f"Error in post-call streaming deployment hook: {e!s}")
verbose_logger.exception(f"Error in post-call streaming deployment hook: {e}")
return chunk
def _add_mcp_list_tools_to_first_chunk(self, chunk: ModelResponseStream) -> ModelResponseStream:
@ -1578,7 +1578,7 @@ class CustomStreamWrapper:
except Exception as e:
from litellm._logging import verbose_logger
verbose_logger.exception(f"Error adding MCP list tools to first chunk: {e!s}")
verbose_logger.exception(f"Error adding MCP list tools to first chunk: {e}")
return chunk
@ -1615,7 +1615,7 @@ class CustomStreamWrapper:
except Exception as e:
from litellm._logging import verbose_logger
verbose_logger.exception(f"Error adding MCP metadata to final chunk: {e!s}")
verbose_logger.exception(f"Error adding MCP metadata to final chunk: {e}")
return chunk

View file

@ -104,7 +104,7 @@ def get_modified_max_tokens(
return user_max_tokens
except Exception as e:
verbose_logger.debug(
f"litellm.litellm_core_utils.token_counter.py::get_modified_max_tokens() - Error while checking max token limit: {e!s}\nmodel={model}, base_model={base_model}"
f"litellm.litellm_core_utils.token_counter.py::get_modified_max_tokens() - Error while checking max token limit: {e}\nmodel={model}, base_model={base_model}"
)
return user_max_tokens

View file

@ -279,7 +279,7 @@ class A2AConfig(BaseConfig):
except Exception as e:
raise A2AError(
status_code=raw_response.status_code,
message=f"Failed to parse A2A response: {e!s}",
message=f"Failed to parse A2A response: {e}",
headers=dict(raw_response.headers),
)

View file

@ -1875,7 +1875,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
except Exception as e:
raise AnthropicError(
status_code=400,
message=f"{e!s}\nReceived Messages={messages}",
message=f"{e}\nReceived Messages={messages}",
) # don't use verbose_logger.exception, if exception is raised
## Auto-strip advisor blocks from history if advisor tool is absent.
@ -2454,7 +2454,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
except Exception as e:
response_headers = getattr(raw_response, "headers", None)
raise AnthropicError(
message=f"Unable to get json response - {e!s}, Original Response: {raw_response.text}",
message=f"Unable to get json response - {e}, Original Response: {raw_response.text}",
status_code=raw_response.status_code,
headers=response_headers,
)

View file

@ -109,14 +109,14 @@ class AnthropicCountTokensHandler(AnthropicCountTokensConfig):
raise
except httpx.HTTPStatusError as e:
# HTTP errors - preserve the actual status code
verbose_logger.error(f"HTTP error in CountTokens handler: {e!s}")
verbose_logger.error(f"HTTP error in CountTokens handler: {e}")
raise AnthropicError(
status_code=e.response.status_code,
message=e.response.text,
)
except Exception as e:
verbose_logger.error(f"Error in CountTokens handler: {e!s}")
verbose_logger.error(f"Error in CountTokens handler: {e}")
raise AnthropicError(
status_code=500,
message=f"CountTokens processing error: {e!s}",
message=f"CountTokens processing error: {e}",
)

View file

@ -684,7 +684,7 @@ class AzureChatCompletion(BaseAzureLLM, BaseLLM):
except json.JSONDecodeError as json_error:
raise AzureOpenAIError(
status_code=raw_response.status_code or 500,
message=f"Failed to parse raw Azure embedding response: {json_error!s}",
message=f"Failed to parse raw Azure embedding response: {json_error}",
) from json_error
if isinstance(response, str):
raise AzureOpenAIError(

View file

@ -333,7 +333,7 @@ def get_azure_ad_token(
verbose_logger.debug("Azure AD Token Provider could not be used.")
except Exception as e:
verbose_logger.error(
f"Error calling Azure AD token provider: {e!s}. Follow docs - https://docs.litellm.ai/docs/providers/azure/#azure-ad-token-refresh---defaultazurecredential"
f"Error calling Azure AD token provider: {e}. Follow docs - https://docs.litellm.ai/docs/providers/azure/#azure-ad-token-refresh---defaultazurecredential"
)
raise e
@ -359,8 +359,8 @@ def get_azure_ad_token(
# Re-raise TypeError directly
raise
except Exception as e:
verbose_logger.error(f"Error calling Azure AD token provider: {e!s}")
raise RuntimeError(f"Failed to get Azure AD token: {e!s}") from e
verbose_logger.error(f"Error calling Azure AD token provider: {e}")
raise RuntimeError(f"Failed to get Azure AD token: {e}") from e
return azure_ad_token
@ -393,7 +393,7 @@ class BaseAzureLLM(BaseOpenAILLM):
verbose_logger.debug("Successfully obtained Azure AD token provider using DefaultAzureCredential")
return azure_ad_token_provider
except Exception as e:
verbose_logger.debug(f"DefaultAzureCredential failed: {e!s}")
verbose_logger.debug(f"DefaultAzureCredential failed: {e}")
return None
def get_azure_openai_client(
@ -508,6 +508,8 @@ class BaseAzureLLM(BaseOpenAILLM):
openai_client=openai_client,
client_initialization_params=client_initialization_params,
client_type="azure",
litellm_owned_client=client is None
and self.owns_wrapped_http_client(azure_client_params.get("http_client")),
)
return openai_client
@ -580,7 +582,7 @@ class BaseAzureLLM(BaseOpenAILLM):
# only show first 5 chars of api_key
_api_key = _api_key[:8] + "*" * 15
verbose_logger.debug(
f"Initializing Azure OpenAI Client for {model_name}, Api Base: {api_base!s}, Api Key:{_api_key}"
f"Initializing Azure OpenAI Client for {model_name}, Api Base: {api_base}, Api Key:{_api_key}"
)
azure_client_params = {
"api_key": api_key,

View file

@ -193,7 +193,7 @@ class AzureAIAgentsHandler:
),
)
except Exception as e:
verbose_logger.warning(f"Failed to calculate token usage: {e!s}")
verbose_logger.warning(f"Failed to calculate token usage: {e}")
return model_response

View file

@ -114,14 +114,14 @@ class AzureAIAnthropicCountTokensHandler(AzureAIAnthropicCountTokensConfig):
raise
except httpx.HTTPStatusError as e:
# HTTP errors - preserve the actual status code
verbose_logger.error(f"HTTP error in CountTokens handler: {e!s}")
verbose_logger.error(f"HTTP error in CountTokens handler: {e}")
raise AnthropicError(
status_code=e.response.status_code,
message=e.response.text,
)
except Exception as e:
verbose_logger.error(f"Error in CountTokens handler: {e!s}")
verbose_logger.error(f"Error in CountTokens handler: {e}")
raise AnthropicError(
status_code=500,
message=f"CountTokens processing error: {e!s}",
message=f"CountTokens processing error: {e}",
)

View file

@ -132,7 +132,7 @@ class AzureAIVectorStoreConfig(BaseVectorStoreConfig, BaseAzureLLM):
)
query_vector = embedding_response.data[0]["embedding"]
except Exception as e:
raise Exception(f"Failed to generate embedding for query: {e!s}")
raise Exception(f"Failed to generate embedding for query: {e}")
# Azure AI Search endpoint for search
index_name = vector_store_id # vector_store_id is the index name

View file

@ -133,7 +133,7 @@ class AzureBlobStorageBackend(BaseFileStorageBackend, AzureBlobStorageLogger):
return storage_url
except Exception as e:
verbose_logger.exception(f"Error uploading file to Azure Blob Storage: {e!s}")
verbose_logger.exception(f"Error uploading file to Azure Blob Storage: {e}")
raise
async def _upload_file_with_account_key(self, file_content: bytes, full_path: str) -> str:
@ -247,7 +247,7 @@ class AzureBlobStorageBackend(BaseFileStorageBackend, AzureBlobStorageLogger):
return await self._download_file_with_azure_ad(file_path)
except Exception as e:
verbose_logger.exception(f"Error downloading file from Azure Blob Storage: {e!s}")
verbose_logger.exception(f"Error downloading file from Azure Blob Storage: {e}")
raise
async def _download_file_with_account_key(self, file_path: str) -> bytes:

View file

@ -186,7 +186,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
return session_id
# Generate a session ID with 33+ characters
generated_id = f"litellm-session-{uuid.uuid4()!s}"
generated_id = f"litellm-session-{uuid.uuid4()}"
verbose_logger.debug(f"Generated new session ID: {generated_id}")
return generated_id
@ -370,7 +370,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
total_tokens=total_tokens,
)
except Exception as e:
verbose_logger.warning(f"Failed to calculate token usage: {e!s}")
verbose_logger.warning(f"Failed to calculate token usage: {e}")
return None
def _parse_json_response(self, response_json: dict) -> AgentCoreParsedResponse:
@ -1023,9 +1023,9 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
return model_response
except Exception as e:
verbose_logger.error(f"Error processing Bedrock AgentCore response: {e!s}")
verbose_logger.error(f"Error processing Bedrock AgentCore response: {e}")
raise BedrockError(
message=f"Error processing response: {e!s}",
message=f"Error processing response: {e}",
status_code=raw_response.status_code,
)

View file

@ -2073,7 +2073,7 @@ class AmazonConverseConfig(BaseConfig):
completion_response = ConverseResponseBlock(**response.json()) # type: ignore
except Exception as e:
raise BedrockError(
message=f"Error converting to valid response block={e!s}. File an issue if litellm error - https://github.com/BerriAI/litellm/issues",
message=f"Error converting to valid response block={e}. File an issue if litellm error - https://github.com/BerriAI/litellm/issues",
status_code=422,
)

View file

@ -464,9 +464,9 @@ class AmazonInvokeAgentConfig(BaseConfig, BaseAWSLLM):
)
except Exception as e:
verbose_logger.error(f"Error processing Bedrock Invoke Agent response: {e!s}")
verbose_logger.error(f"Error processing Bedrock Invoke Agent response: {e}")
raise BedrockError(
message=f"Error processing response: {e!s}",
message=f"Error processing response: {e}",
status_code=raw_response.status_code,
)

View file

@ -590,7 +590,7 @@ class AWSEventStreamDecoder:
return response
except Exception as e:
raise Exception(f"Received streaming error - {e!s}")
raise Exception(f"Received streaming error - {e}")
def _chunk_parser(self, chunk_data: dict) -> Union[GChunk, ModelResponseStream, dict]:
text = ""

View file

@ -208,7 +208,7 @@ class AmazonTwelveLabsPegasusConfig(AmazonInvokeConfig, BaseConfig):
completion_response = raw_response.json()
except Exception as e:
raise BedrockError(
message=f"Error parsing response: {raw_response.text}, error: {e!s}",
message=f"Error parsing response: {raw_response.text}, error: {e}",
status_code=raw_response.status_code,
)
@ -237,7 +237,7 @@ class AmazonTwelveLabsPegasusConfig(AmazonInvokeConfig, BaseConfig):
raise Exception("Unable to set message content")
except Exception as e:
raise BedrockError(
message=f"Error setting response content: {e!s}. Response: {completion_response}",
message=f"Error setting response content: {e}. Response: {completion_response}",
status_code=raw_response.status_code,
)

View file

@ -356,7 +356,7 @@ class AmazonInvokeConfig(BaseConfig, BaseAWSLLM):
outputText = completion_response.get("results")[0].get("outputText")
except Exception as e:
raise BedrockError(
message=f"Error processing={raw_response.text}, Received error={e!s}",
message=f"Error processing={raw_response.text}, Received error={e}",
status_code=422,
)
@ -379,7 +379,7 @@ class AmazonInvokeConfig(BaseConfig, BaseAWSLLM):
raise Exception()
except Exception as e:
raise BedrockError(
message=f"Error parsing received text={outputText}.\nError-{e!s}",
message=f"Error parsing received text={outputText}.\nError-{e}",
status_code=raw_response.status_code,
)

View file

@ -120,14 +120,14 @@ class BedrockCountTokensHandler(BedrockCountTokensConfig):
raise
except httpx.HTTPStatusError as e:
# HTTP errors - preserve the actual status code
verbose_logger.error(f"HTTP error in CountTokens handler: {e!s}")
verbose_logger.error(f"HTTP error in CountTokens handler: {e}")
raise BedrockError(
status_code=e.response.status_code,
message=e.response.text,
)
except Exception as e:
verbose_logger.error(f"Error in CountTokens handler: {e!s}")
verbose_logger.error(f"Error in CountTokens handler: {e}")
raise BedrockError(
status_code=500,
message=f"CountTokens processing error: {e!s}",
message=f"CountTokens processing error: {e}",
)

View file

@ -130,7 +130,7 @@ class BedrockFilesHandler(BaseAWSLLM):
response = s3_client.get_object(Bucket=bucket_name, Key=object_key)
file_content = response["Body"].read()
except Exception as e:
raise ValueError(f"Failed to download file from S3: {s3_uri}. Error: {e!s}")
raise ValueError(f"Failed to download file from S3: {s3_uri}. Error: {e}")
# Create mock HTTP response
mock_response = httpx.Response(

View file

@ -652,7 +652,7 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig):
)
except Exception as e:
verbose_logger.exception(
f"litellm.llms.bedrock.files.transformation.py::_transform_openai_jsonl_content_to_bedrock_jsonl_content() - Error inferring custom_llm_provider - {e!s}"
f"litellm.llms.bedrock.files.transformation.py::_transform_openai_jsonl_content_to_bedrock_jsonl_content() - Error inferring custom_llm_provider - {e}"
)
# Determine provider from model name

View file

@ -175,7 +175,7 @@ class BedrockRealtime(BaseAWSLLM):
except Exception as e:
verbose_proxy_logger.exception(f"Error in BedrockRealtime.async_realtime: {e}")
try:
await websocket.close(code=1011, reason=_redact_string(f"Internal error: {e!s}"))
await websocket.close(code=1011, reason=_redact_string(f"Internal error: {e}"))
except Exception:
pass
raise

View file

@ -159,7 +159,7 @@ class BlackForestLabsImageEdit:
except Exception as e:
raise BlackForestLabsError(
status_code=500,
message=f"Request failed: {e!s}",
message=f"Request failed: {e}",
)
# Poll for result
@ -262,7 +262,7 @@ class BlackForestLabsImageEdit:
except Exception as e:
raise BlackForestLabsError(
status_code=500,
message=f"Request failed: {e!s}",
message=f"Request failed: {e}",
)
# Poll for result

View file

@ -156,7 +156,7 @@ class BlackForestLabsImageGeneration:
except Exception as e:
raise BlackForestLabsError(
status_code=500,
message=f"Request failed: {e!s}",
message=f"Request failed: {e}",
)
# Poll for result
@ -262,7 +262,7 @@ class BlackForestLabsImageGeneration:
except Exception as e:
raise BlackForestLabsError(
status_code=500,
message=f"Request failed: {e!s}",
message=f"Request failed: {e}",
)
# Poll for result

View file

@ -106,7 +106,7 @@ class ClarifaiConfig(OpenAIGPTConfig):
except Exception as e:
raise OpenAIError(
status_code=raw_response.status_code,
message=f"Failed to parse Clarifai response: {e!s}",
message=f"Failed to parse Clarifai response: {e}",
headers=raw_response.headers,
) from e

View file

@ -356,7 +356,7 @@ class CodestralTextCompletion:
)
except Exception as e:
raise TextCompletionCodestralError(
status_code=500, message=f"{e!s}"
status_code=500, message=f"{e}"
) # don't use verbose_logger.exception, if exception is raised
return self.process_text_completion_response(
model=model,

View file

@ -1411,6 +1411,7 @@ def get_async_httpx_client(
key=_cache_key_name,
value=_new_client,
ttl=_DEFAULT_TTL_FOR_HTTPX_CLIENTS,
litellm_owned_client=True,
)
return _new_client
@ -1456,5 +1457,6 @@ def _get_httpx_client(params: dict | None = None) -> HTTPHandler:
key=_cache_key_name,
value=_new_client,
ttl=_DEFAULT_TTL_FOR_HTTPX_CLIENTS,
litellm_owned_client=True,
)
return _new_client

View file

@ -5659,7 +5659,7 @@ class BaseLLMHTTPHandler:
fingerprint=fingerprint,
)
except Exception as e:
verbose_logger.exception(f"LiteLLM.AgenticHookError: Exception in chat completion agentic hooks: {e!s}")
verbose_logger.exception(f"LiteLLM.AgenticHookError: Exception in chat completion agentic hooks: {e}")
# Check if we need to convert response to fake stream for chat completions
# This happens when:
@ -5906,7 +5906,7 @@ class BaseLLMHTTPHandler:
except Exception as e:
verbose_logger.exception(f"Error connecting to backend: {e}")
try:
await websocket.close(code=1011, reason=_redact_string(f"Internal server error: {e!s}"))
await websocket.close(code=1011, reason=_redact_string(f"Internal server error: {e}"))
except RuntimeError as close_error:
if "already completed" in str(close_error) or "websocket.close" in str(close_error):
# The WebSocket is already closed or the response is completed, so we can ignore this error
@ -6303,7 +6303,7 @@ class BaseLLMHTTPHandler:
except Exception as e:
verbose_logger.exception(f"Error in responses WS: {e}")
try:
await websocket.close(code=1011, reason=_redact_string(f"Internal server error: {e!s}"))
await websocket.close(code=1011, reason=_redact_string(f"Internal server error: {e}"))
except RuntimeError as close_error:
if "already completed" in str(close_error) or "websocket.close" in str(close_error):
pass

View file

@ -130,7 +130,7 @@ class DashScopeEmbeddingConfig(BaseEmbeddingConfig):
except Exception as e:
raise DashScopeError(
status_code=raw_response.status_code,
message=f"Failed to parse DashScope response as JSON: {e!s}",
message=f"Failed to parse DashScope response as JSON: {e}",
)
logging_obj.post_call(

View file

@ -630,7 +630,7 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig):
except Exception as e:
response_headers = getattr(raw_response, "headers", None)
raise DatabricksException(
message=f"Unable to get json response - {e!s}, Original Response: {raw_response.text}",
message=f"Unable to get json response - {e}, Original Response: {raw_response.text}",
status_code=raw_response.status_code,
headers=response_headers,
)

View file

@ -245,7 +245,7 @@ class DatabricksBase:
except requests.RequestException as e:
raise DatabricksException(
status_code=500,
message=f"OAuth M2M token request failed: {e!s}",
message=f"OAuth M2M token request failed: {e}",
)
if response.status_code != 200:

View file

@ -122,7 +122,7 @@ class DeepgramAudioTranscriptionConfig(BaseAudioTranscriptionConfig):
return response
except Exception as e:
raise ValueError(f"Error transforming Deepgram response: {e!s}\nResponse: {raw_response.text}")
raise ValueError(f"Error transforming Deepgram response: {e}\nResponse: {raw_response.text}")
def _reconstruct_diarized_transcript(self, words: list) -> str:
"""

View file

@ -144,7 +144,7 @@ class ElevenLabsAudioTranscriptionConfig(BaseAudioTranscriptionConfig):
return response
except Exception as e:
raise ValueError(f"Error transforming ElevenLabs response: {e!s}\nResponse: {raw_response.text}")
raise ValueError(f"Error transforming ElevenLabs response: {e}\nResponse: {raw_response.text}")
def get_complete_url(
self,

View file

@ -542,7 +542,7 @@ class FireworksAIConfig(FireworksAIMixin, OpenAIGPTConfig):
except Exception as e:
response_headers = getattr(raw_response, "headers", None)
raise FireworksAIException(
message=f"Unable to get json response - {e!s}, Original Response: {raw_response.text}",
message=f"Unable to get json response - {e}, Original Response: {raw_response.text}",
status_code=raw_response.status_code,
headers=response_headers,
)

View file

@ -178,7 +178,7 @@ class FireworksAIRerankConfig(FireworksAIMixin, BaseRerankConfig):
raw_response_json = raw_response.json()
except Exception as e:
raise self.get_error_class(
error_message=f"Failed to parse response: {e!s}",
error_message=f"Failed to parse response: {e}",
status_code=raw_response.status_code,
headers=raw_response.headers,
)

View file

@ -220,7 +220,7 @@ class GDCGeminiConfig(OpenAILikeChatConfig):
AttributeError,
) as e:
raise litellm.utils.AuthenticationError(
message=f"Failed to load service account credentials from api_key: {e!s}",
message=f"Failed to load service account credentials from api_key: {e}",
llm_provider="gdc",
model=model,
) from e

View file

@ -155,8 +155,8 @@ class GoogleAIStudioTokenCounter:
status_code=e.response.status_code,
) from e
except httpx.RequestError as e:
error_msg = f"Request to Google Gen AI Studio failed: {e!s}"
error_msg = f"Request to Google Gen AI Studio failed: {e}"
raise litellm.APIConnectionError(message=error_msg, llm_provider="gemini", model=model) from e
except Exception as e:
error_msg = f"Unexpected error during token counting: {e!s}"
error_msg = f"Unexpected error during token counting: {e}"
raise Exception(error_msg) from e

View file

@ -190,8 +190,8 @@ class GoogleAIStudioFilesHandler(GeminiModelInfo, BaseFilesConfig):
status_details=None,
)
except Exception as e:
verbose_logger.exception(f"Error parsing file upload response: {e!s}")
raise ValueError(f"Error parsing file upload response: {e!s}")
verbose_logger.exception(f"Error parsing file upload response: {e}")
raise ValueError(f"Error parsing file upload response: {e}")
def transform_retrieve_file_request(
self,
@ -294,8 +294,8 @@ class GoogleAIStudioFilesHandler(GeminiModelInfo, BaseFilesConfig):
status_details=(str(response_json.get("error", "")) if gemini_state == "FAILED" else None),
)
except Exception as e:
verbose_logger.exception(f"Error parsing file retrieve response: {e!s}")
raise ValueError(f"Error parsing file retrieve response: {e!s}")
verbose_logger.exception(f"Error parsing file retrieve response: {e}")
raise ValueError(f"Error parsing file retrieve response: {e}")
def transform_delete_file_request(
self,
@ -362,8 +362,8 @@ class GoogleAIStudioFilesHandler(GeminiModelInfo, BaseFilesConfig):
else:
raise ValueError(f"Failed to delete file: {raw_response.text}")
except Exception as e:
verbose_logger.exception(f"Error parsing file delete response: {e!s}")
raise ValueError(f"Error parsing file delete response: {e!s}")
verbose_logger.exception(f"Error parsing file delete response: {e}")
raise ValueError(f"Error parsing file delete response: {e}")
def transform_list_files_request(
self,

View file

@ -256,7 +256,7 @@ class GeminiVectorStoreConfig(BaseVectorStoreConfig):
except Exception as e:
raise self.get_error_class(
error_message=f"Failed to parse Gemini response: {e!s}",
error_message=f"Failed to parse Gemini response: {e}",
status_code=response.status_code,
headers=response.headers,
)
@ -327,7 +327,7 @@ class GeminiVectorStoreConfig(BaseVectorStoreConfig):
except Exception as e:
raise self.get_error_class(
error_message=f"Failed to parse Gemini create response: {e!s}",
error_message=f"Failed to parse Gemini create response: {e}",
status_code=response.status_code,
headers=response.headers,
)

View file

@ -177,7 +177,7 @@ def _request_token_sync(
except httpx.RequestError as e:
raise GigaChatAuthError(
status_code=500,
message=f"GigaChat authentication request failed: {e!s}",
message=f"GigaChat authentication request failed: {e}",
)
@ -212,7 +212,7 @@ async def _request_token_async(
except httpx.RequestError as e:
raise GigaChatAuthError(
status_code=500,
message=f"GigaChat authentication request failed: {e!s}",
message=f"GigaChat authentication request failed: {e}",
)

View file

@ -68,7 +68,7 @@ class Authenticator:
verbose_logger.error("Error saving access token to file")
return access_token
except (GetDeviceCodeError, GetAccessTokenError, RefreshAPIKeyError) as e:
verbose_logger.warning(f"Failed attempt {attempt + 1}: {e!s}")
verbose_logger.warning(f"Failed attempt {attempt + 1}: {e}")
continue
raise GetAccessTokenError(
@ -100,7 +100,7 @@ class Authenticator:
except OSError:
verbose_logger.warning("No API key file found or error opening file")
except (json.JSONDecodeError, KeyError) as e:
verbose_logger.warning(f"Error reading API key from file: {e!s}")
verbose_logger.warning(f"Error reading API key from file: {e}")
except APIKeyExpiredError:
pass # Already logged in the try block
@ -117,14 +117,14 @@ class Authenticator:
status_code=401,
)
except OSError as e:
verbose_logger.error(f"Error saving API key to file: {e!s}")
verbose_logger.error(f"Error saving API key to file: {e}")
raise GetAPIKeyError(
message=f"Failed to save API key: {e!s}",
message=f"Failed to save API key: {e}",
status_code=500,
)
except RefreshAPIKeyError as e:
raise GetAPIKeyError(
message=f"Failed to refresh API key: {e!s}",
message=f"Failed to refresh API key: {e}",
status_code=401,
)
@ -142,7 +142,7 @@ class Authenticator:
api_endpoint = endpoints.get("api")
return api_endpoint
except (OSError, json.JSONDecodeError, KeyError) as e:
verbose_logger.warning(f"Error reading API endpoint from file: {e!s}")
verbose_logger.warning(f"Error reading API endpoint from file: {e}")
return None
def _refresh_api_key(self) -> dict[str, Any]:
@ -173,9 +173,9 @@ class Authenticator:
else:
verbose_logger.warning(f"API key response missing token: {response_json}")
except httpx.HTTPStatusError as e:
verbose_logger.error(f"HTTP error refreshing API key (attempt {attempt + 1}/{max_retries}): {e!s}")
verbose_logger.error(f"HTTP error refreshing API key (attempt {attempt + 1}/{max_retries}): {e}")
except Exception as e:
verbose_logger.error(f"Unexpected error refreshing API key: {e!s}")
verbose_logger.error(f"Unexpected error refreshing API key: {e}")
raise RefreshAPIKeyError(
message="Failed to refresh API key after maximum retries",
@ -245,21 +245,21 @@ class Authenticator:
return resp_json
except httpx.HTTPStatusError as e:
verbose_logger.error(f"HTTP error getting device code: {e!s}")
verbose_logger.error(f"HTTP error getting device code: {e}")
raise GetDeviceCodeError(
message=f"Failed to get device code: {e!s}",
message=f"Failed to get device code: {e}",
status_code=400,
)
except json.JSONDecodeError as e:
verbose_logger.error(f"Error decoding JSON response: {e!s}")
verbose_logger.error(f"Error decoding JSON response: {e}")
raise GetDeviceCodeError(
message=f"Failed to decode device code response: {e!s}",
message=f"Failed to decode device code response: {e}",
status_code=400,
)
except Exception as e:
verbose_logger.error(f"Unexpected error getting device code: {e!s}")
verbose_logger.error(f"Unexpected error getting device code: {e}")
raise GetDeviceCodeError(
message=f"Failed to get device code: {e!s}",
message=f"Failed to get device code: {e}",
status_code=400,
)
@ -304,21 +304,21 @@ class Authenticator:
else:
verbose_logger.warning(f"Unexpected response: {resp_json}")
except httpx.HTTPStatusError as e:
verbose_logger.error(f"HTTP error polling for access token: {e!s}")
verbose_logger.error(f"HTTP error polling for access token: {e}")
raise GetAccessTokenError(
message=f"Failed to get access token: {e!s}",
message=f"Failed to get access token: {e}",
status_code=400,
)
except json.JSONDecodeError as e:
verbose_logger.error(f"Error decoding JSON response: {e!s}")
verbose_logger.error(f"Error decoding JSON response: {e}")
raise GetAccessTokenError(
message=f"Failed to decode access token response: {e!s}",
message=f"Failed to decode access token response: {e}",
status_code=400,
)
except Exception as e:
verbose_logger.error(f"Unexpected error polling for access token: {e!s}")
verbose_logger.error(f"Unexpected error polling for access token: {e}")
raise GetAccessTokenError(
message=f"Failed to get access token: {e!s}",
message=f"Failed to get access token: {e}",
status_code=400,
)

Some files were not shown because too many files have changed in this diff Show more