From 44862f0dc953934e409e2a5ee6357c40036cb3ef Mon Sep 17 00:00:00 2001 From: Harshil Kaneria Date: Tue, 3 Nov 2026 00:18:03 +0530 Subject: [PATCH] fix(logging): leave oversized bodies out of the raw request log With log_raw_request_response on, every request builds a curl string of the full body and runs secret redaction over it on the event loop. For a 16 MB body that blocks the proxy for seconds, so liveness probes time out and the pod restarts Bodies longer than MAX_RAW_REQUEST_BODY_LOG_CHARS (default 1,000,000) are now replaced by a short placeholder in the curl string, which keeps the URL and masked headers. raw_request_typed_dict still holds the full body Fixes #49673 --- litellm/constants.py | 1 + litellm/litellm_core_utils/litellm_logging.py | 6 ++++- .../test_litellm_logging.py | 24 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/litellm/constants.py b/litellm/constants.py index cd7c0176428..5d250da5d72 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -2184,6 +2184,7 @@ MICROSOFT_USER_LAST_NAME_ATTRIBUTE: Final = str(os.getenv("MICROSOFT_USER_LAST_N # Maximum payload size (in bytes) to fully serialize for DEBUG logging. # Payloads larger than this are truncated to avoid multi-second json.dumps blocking the response. MAX_PAYLOAD_SIZE_FOR_DEBUG_LOG: Final = get_env_int("MAX_PAYLOAD_SIZE_FOR_DEBUG_LOG", 102400) # 100 KB +MAX_RAW_REQUEST_BODY_LOG_CHARS: Final = get_env_int("MAX_RAW_REQUEST_BODY_LOG_CHARS", 1_000_000) # Policy template enrichment MAX_COMPETITOR_NAMES: Final = get_env_int("MAX_COMPETITOR_NAMES", 100) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 639003c9a6a..07e1d8324a9 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -47,6 +47,7 @@ from litellm.constants import ( INTERNAL_CALLBACK_NAMES, KUBERNETES_POD_ROUTING_KEY, LITELLM_LOGGING_NO_UPSTREAM_LLM_CALL, + MAX_RAW_REQUEST_BODY_LOG_CHARS, PROVIDER_REQUEST_ID_HEADERS, REALTIME_METERED_USAGE_KEY, REDACTED_BY_LITELLM, @@ -1830,7 +1831,10 @@ class Logging(LiteLLMLoggingBaseClass): verbose_logger.debug("\x1b[92m%s\x1b[0m\n", curl_command) def _get_request_body(self, data: dict) -> str: - return str(data) + body: Final = str(data) + if len(body) > MAX_RAW_REQUEST_BODY_LOG_CHARS: + return f"<{len(body)} chars omitted, over MAX_RAW_REQUEST_BODY_LOG_CHARS={MAX_RAW_REQUEST_BODY_LOG_CHARS}>" + return body def _get_request_curl_command(self, api_base: str, headers: dict | None, additional_args: dict, data: dict) -> str: masked_api_base: Final = self._get_masked_api_base(api_base) diff --git a/tests/unit/litellm_core_utils/test_litellm_logging.py b/tests/unit/litellm_core_utils/test_litellm_logging.py index f1854563cd5..13d6edaf937 100644 --- a/tests/unit/litellm_core_utils/test_litellm_logging.py +++ b/tests/unit/litellm_core_utils/test_litellm_logging.py @@ -8662,6 +8662,30 @@ def test_pre_call_redacts_and_masks_raw_request(logging_obj): assert "key=*****" in raw_api_base +def test_pre_call_omits_raw_request_body_over_size_limit(logging_obj, monkeypatch): + """Redacting a multi-MB raw request blocks the event loop, so an oversized body is left out of it.""" + monkeypatch.setattr("litellm.litellm_core_utils.litellm_logging.MAX_RAW_REQUEST_BODY_LOG_CHARS", 100) + metadata = {"user_api_key_alias": "qa-key"} + logging_obj.model_call_details["litellm_params"] = {"metadata": metadata} + logging_obj.log_raw_request_response = True + body = {"messages": [{"role": "user", "content": "PRIVATE-PHRASE " * 20}]} + + logging_obj.pre_call( + input="hi", + api_key="", + additional_args={ + "api_base": "https://api.openai.com/v1/chat/completions", + "headers": {}, + "complete_input_dict": body, + }, + ) + + raw_request = metadata["raw_request"] + assert "PRIVATE-PHRASE" not in raw_request + assert "https://api.openai.com/v1/chat/completions" in raw_request + assert logging_obj.model_call_details["raw_request_typed_dict"]["raw_request_body"] == body + + _PRIVATE_RAW_REQUEST_ARGS: Final = { "api_base": "https://api.openai.com/v1/chat/completions", "headers": {},