Skip to content

fix(proxy): exclude proxy_server_request from its own body snapshot#28618

Merged
mateo-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_fix_proxy_server_request_body_self_reference
May 26, 2026
Merged

fix(proxy): exclude proxy_server_request from its own body snapshot#28618
mateo-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_fix_proxy_server_request_body_self_reference

Conversation

@michelligabriele

Copy link
Copy Markdown
Collaborator

Relevant issues

n/a — internal bug found while investigating the redaction-gaps work in PR #28611. Independent file/owner, shipping separately.

Linear ticket

n/a

Pre-Submission checklist

  • I have Added testing in the tests/test_litellm/ directory — added test_add_litellm_data_to_request_body_snapshot_excludes_proxy_server_request in tests/test_litellm/proxy/test_litellm_pre_call_utils.py, mirroring the existing _excludes_secret_fields regression test.
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Delays in PR merge?

n/a

CI (LiteLLM team)

  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Screenshots / Proof of Fix

Beforeadd_litellm_data_to_request writes the body snapshot at the end of pre-call processing:

_body_snapshot = {k: v for k, v in data.items() if k != "secret_fields"}
data["proxy_server_request"]["body"] = _body_snapshot

At that point data["proxy_server_request"] was already set earlier in the same function, so the snapshot includes it and body self-references:

body["proxy_server_request"]["body"] is body["proxy_server_request"]

Any consumer that walks proxy_server_request.body (custom loggers, spend-tracking, audit exporters) hits an infinite loop. Reproduced on a test proxy by inspecting the kwargs payload passed to a CustomLogger.async_log_success_event hook — the body dict's KEYS include proxy_server_request on every successful call, regardless of redaction.

Afterproxy_server_request is added to the snapshot exclude set alongside secret_fields. Same repro proxy, same hook, body's KEYS no longer include proxy_server_request on any of three test requests (baseline / redaction header non-reasoning / redaction header reasoning). New regression test covers it.

# inspect_dumps.py on the patched proxy
[ISSUE 2  ✓]  OK — 'proxy_server_request' appears 1× (expect 1)

(Pre-fix this read — one legitimate occurrence at litellm_params.proxy_server_request, one in the self-referenced snapshot.)

Type

🐛 Bug Fix

Changes

litellm/proxy/litellm_pre_call_utils.py — one-line behavior change in add_litellm_data_to_request. The body snapshot exclude set goes from {\"secret_fields\"} to {\"secret_fields\", \"proxy_server_request\"}:

-    _body_snapshot = {k: v for k, v in data.items() if k != "secret_fields"}
+    _body_snapshot_exclude = {"secret_fields", "proxy_server_request"}
+    _body_snapshot = {k: v for k, v in data.items() if k not in _body_snapshot_exclude}
     data["proxy_server_request"]["body"] = _body_snapshot

Comment block above the snapshot updated to explain both exclusions (was: secret_fields only; now: secret_fields + the self-reference explanation for proxy_server_request).

tests/test_litellm/proxy/test_litellm_pre_call_utils.py — added test_add_litellm_data_to_request_body_snapshot_excludes_proxy_server_request. Asserts "proxy_server_request" not in updated["proxy_server_request"]["body"].

Known follow-up, intentionally out of scope: the body snapshot also drags in other pipeline-internal keys (litellm_call_id, litellm_trace_id, user_api_key_*, api_version, ttl) that were never part of the user POST body. Broadening the exclude set risks breaking downstream consumers that read those keys today — flagging as a follow-up rather than bundling here.

@codecov

codecov Bot commented May 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a self-referencing loop in the proxy_server_request body snapshot by adding proxy_server_request to the exclude set alongside the existing secret_fields exclusion in add_litellm_data_to_request. The bug caused body["proxy_server_request"]["body"] to point back to the same dict as body, which would trigger infinite traversal in any custom logger or audit consumer that walked the structure.

  • litellm/proxy/litellm_pre_call_utils.py: Expands the one-liner snapshot filter into a named exclude set {"secret_fields", "proxy_server_request"}; updated comment block explains both exclusions clearly.
  • tests/test_litellm/proxy/test_litellm_pre_call_utils.py: Adds test_add_litellm_data_to_request_body_snapshot_excludes_proxy_server_request, a pure-mock regression test asserting "proxy_server_request" not in updated["proxy_server_request"]["body"], matching the style of the existing _excludes_secret_fields test.

Confidence Score: 5/5

Safe to merge — the change is a minimal, well-scoped fix with a direct regression test and no observable side effects on correct code paths.

The fix is a single dict-comprehension filter change that removes a pathological self-reference from the body snapshot. The updated comment clearly explains both exclusions. The new regression test follows the established pattern in the file, uses only mocks, and directly asserts the invariant that was previously broken. No existing tests are modified, and the behavioral change only removes a key that was producing broken (self-referential) output anyway.

No files require special attention.

Important Files Changed

Filename Overview
litellm/proxy/litellm_pre_call_utils.py One-line behavioral fix: adds proxy_server_request to the body snapshot exclude set to prevent the dict from self-referencing and causing infinite traversal loops in downstream consumers.
tests/test_litellm/proxy/test_litellm_pre_call_utils.py Adds a new regression test mirroring the existing _excludes_secret_fields test; uses mocks only with no real network calls, consistent with the test directory rules.

Reviews (1): Last reviewed commit: "fix(proxy): exclude proxy_server_request..." | Re-trigger Greptile

@mateo-berri mateo-berri left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; thanks!

@mateo-berri mateo-berri merged commit 9c0a98c into litellm_internal_staging May 26, 2026
115 of 116 checks passed
@mateo-berri mateo-berri deleted the litellm_fix_proxy_server_request_body_self_reference branch May 26, 2026 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants