fix: redaction headers ignored when sent via proxy#20740
fix: redaction headers ignored when sent via proxy#20740tsachis wants to merge 2 commits intoBerriAI:mainfrom
Conversation
When requests go through the proxy, `litellm_params["litellm_metadata"]` is always set (even when `None`), so `get_metadata_variable_name_from_kwargs` always returns "litellm_metadata". The redaction code then reads `None` instead of the actual metadata dict that contains the headers. Add a fallback to read from `metadata` when `litellm_metadata` is not a dict, so `x-litellm-enable-message-redaction` and related headers work correctly in the proxy flow. Fixes BerriAI#20739 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile OverviewGreptile SummaryThis PR fixes message-redaction headers being ignored in the proxy flow by updating The change fits into the existing redaction decision path by ensuring request headers are actually read from the proxy-populated metadata structure, so the existing header-based enable/disable behavior works consistently across call paths. Confidence Score: 4/5
|
| Filename | Overview |
|---|---|
| litellm/litellm_core_utils/redact_messages.py | Adds a fallback in should_redact_message_logging() to read headers from metadata when litellm_metadata is present but None, fixing proxy requests that previously ignored redaction headers. |
| tests/test_litellm/litellm_core_utils/test_redact_messages.py | Adds unit tests covering proxy vs SDK metadata locations and precedence between dynamic params, headers, and global setting for message redaction. |
Sequence Diagram
sequenceDiagram
participant Client
participant Proxy as LiteLLM Proxy
participant Redact as should_redact_message_logging
Client->>Proxy: Request + headers
Note over Proxy: Proxy builds model_call_details
Proxy->>Redact: model_call_details
Redact->>Redact: litellm_params = model_call_details["litellm_params"]
Redact->>Redact: metadata_field = get_metadata_variable_name_from_kwargs(litellm_params)
Redact->>Redact: metadata = litellm_params[metadata_field]
alt metadata is dict
Redact->>Redact: request_headers = metadata["headers"]
else metadata is None/non-dict
Note over Redact: Fix: fallback to litellm_params["metadata"]
Redact->>Redact: metadata = litellm_params["metadata"]
Redact->>Redact: request_headers = metadata["headers"]
end
Redact-->>Proxy: boolean (redact?)
Proxy-->>Client: Response (logging redacted per decision)
|
|
||
| metadata_field = get_metadata_variable_name_from_kwargs(litellm_params) | ||
| metadata = litellm_params.get(metadata_field, {}) | ||
|
|
||
| if not isinstance(metadata, dict): |
There was a problem hiding this comment.
Non-dict metadata fallback
If litellm_params[metadata_field] is present but not a dict (e.g. None), the code falls back to litellm_params["metadata"] without re-validating it’s a dict. If metadata is also None/non-dict, metadata.get("headers") will raise. Consider normalizing after the fallback (e.g., metadata = metadata if isinstance(metadata, dict) else {}) so the function always handles non-dict inputs safely.
There was a problem hiding this comment.
Good catch! Fixed in 37f9bb7 — added a second isinstance check after the fallback so metadata is always normalized to {} when both fields are non-dict. Also added tests for the case where both litellm_metadata and metadata are None.
After falling back from litellm_metadata to metadata, ensure the value
is always a dict so .get("headers") never raises on None/non-dict inputs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
|
Summary
x-litellm-enable-message-redactionandlitellm-enable-message-redactionheaders being silently ignored when requests go through the proxyshould_redact_message_logging()to read frommetadatawhenlitellm_metadataisNonelitellm-disable-message-redactionheader is also fixed by this changeRoot cause
get_litellm_params()always includes"litellm_metadata"as a key (even whenNone), soget_metadata_variable_name_from_kwargs()always returns"litellm_metadata". The redaction function then readsNoneinstead of the actualmetadatadict that contains the headers.Fix
In
should_redact_message_logging(), when the resolved metadata field is not a dict (i.e.None), fall back tolitellm_params.get("metadata", {}).Fixes #20739
Test plan
tests/test_litellm/litellm_core_utils/test_redact_messages.pycovering:x-litellm-enable-message-redactionheader (proxy flow)litellm-enable-message-redactionheader (proxy flow)litellm-disable-message-redactionheader (proxy flow)litellm_metadata(SDK direct call)test_redact_msgs_from_logs,test_redact_msgs_from_logs_with_dynamic_params🤖 Generated with Claude Code