diff --git a/litellm/proxy/auth/auth_exception_handler.py b/litellm/proxy/auth/auth_exception_handler.py index e19bb3f9f5f..bd682e98a59 100644 --- a/litellm/proxy/auth/auth_exception_handler.py +++ b/litellm/proxy/auth/auth_exception_handler.py @@ -94,6 +94,14 @@ class UserAPIKeyAuthExceptionHandler: request=request, use_x_forwarded_for=general_settings.get("use_x_forwarded_for", False), ) + request_metadata = request_data.get("metadata") + request_data_with_ip = { + **request_data, + "metadata": { + **(request_metadata if isinstance(request_metadata, dict) else {}), + "requester_ip_address": requester_ip, + }, + } verbose_proxy_logger.exception( "litellm.proxy.proxy_server.user_api_key_auth(): Exception occured - {}\nRequester IP Address:{}".format( str(e), @@ -134,7 +142,7 @@ class UserAPIKeyAuthExceptionHandler: # Allow callbacks to transform the error response transformed_exception = await proxy_logging_obj.post_call_failure_hook( - request_data=request_data, + request_data=request_data_with_ip, original_exception=e, user_api_key_dict=user_api_key_dict, error_type=ProxyErrorTypes.auth_error, diff --git a/tests/test_litellm/proxy/auth/test_auth_exception_handler.py b/tests/test_litellm/proxy/auth/test_auth_exception_handler.py index 11e6f483e35..dd1207a0946 100644 --- a/tests/test_litellm/proxy/auth/test_auth_exception_handler.py +++ b/tests/test_litellm/proxy/auth/test_auth_exception_handler.py @@ -423,6 +423,18 @@ async def test_auth_failure_without_resolved_identity_still_logs(): the handler must still log a usable object carrying the raw api key and route, not crash on the missing identity.""" handler = UserAPIKeyAuthExceptionHandler() + request = Request( + { + "type": "http", + "method": "POST", + "path": "/v1/chat/completions", + "headers": [], + "client": ("203.0.113.42", 45678), + "scheme": "http", + "server": ("testserver", 80), + "query_string": b"", + } + ) with ( patch( @@ -445,7 +457,7 @@ async def test_auth_failure_without_resolved_identity_still_logs(): param=None, code=status.HTTP_401_UNAUTHORIZED, ), - MagicMock(), + request, {}, "/v1/chat/completions", None, @@ -453,8 +465,10 @@ async def test_auth_failure_without_resolved_identity_still_logs(): ) logged = mock_hook.call_args[1]["user_api_key_dict"] + logged_request_data = mock_hook.call_args[1]["request_data"] # Raw key must NOT land on the object — it would be promoted into telemetry # as litellm.api_key.hash and leak a real sk-... to anyone reading the trace. assert logged.api_key != "sk-unknown" assert logged.api_key == UserAPIKeyAuth(api_key="sk-unknown").api_key assert logged.request_route == "/v1/chat/completions" + assert logged_request_data["metadata"]["requester_ip_address"] == "203.0.113.42"