From 080145ff81851e66ed1715cc24e23bd5607b2484 Mon Sep 17 00:00:00 2001 From: VimalN2005 Date: Sun, 18 Oct 2026 23:03:48 +0530 Subject: [PATCH] fix(proxy/logging): case-insensitive header lookup in _get_extra_header_tags (#46847) Signed-off-by: VimalN2005 --- litellm/litellm_core_utils/litellm_logging.py | 15 ++++++++++----- .../litellm_core_utils/test_litellm_logging.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 5d9652cc8a2..f87bd63655d 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -6841,13 +6841,18 @@ class StandardLoggingPayloadSetup: headers: Final = proxy_server_request.get("headers", {}) if not isinstance(headers, dict): return None - request_headers: Final = cast( # cast-ok: request headers are untyped framework data - dict[str, str], headers - ) - header_tags: Final = [] + # Headers are case-insensitive per RFC 7230 / RFC 9110. + # Normalize header keys to lowercase to ensure tags are captured regardless of request casing. + normalized_headers: Final[dict[str, str]] = { + str(k).lower(): str(v) + for k, v in headers.items() + if v is not None + } + + header_tags: Final[list[str]] = [] for header_name in extra_headers: - header_value = request_headers.get(header_name) + header_value = normalized_headers.get(header_name.lower()) if header_value: header_tags.append(f"{header_name}: {header_value}") diff --git a/tests/unit/litellm_core_utils/test_litellm_logging.py b/tests/unit/litellm_core_utils/test_litellm_logging.py index e392ee746b3..0f83f95cbbc 100644 --- a/tests/unit/litellm_core_utils/test_litellm_logging.py +++ b/tests/unit/litellm_core_utils/test_litellm_logging.py @@ -3432,6 +3432,21 @@ def test_get_extra_header_tags(): assert "x-custom: my-value" in result assert "x-empty:" not in str(result) + # Test case 8: Case-insensitive header matching (RFC 7230 / RFC 9110) + litellm.extra_spend_tag_headers = ["x-session-id", "X-Organization-ID"] + result = StandardLoggingPayloadSetup._get_extra_header_tags( + proxy_server_request={ + "headers": { + "X-Session-Id": "sess_123", + "x-organization-id": "org_456", + } + } + ) + assert result is not None + assert len(result) == 2 + assert "x-session-id: sess_123" in result + assert "X-Organization-ID: org_456" in result + finally: # Restore original value if original_extra_headers is not None: