Skip to content

test(pass-through): de-flake vertex spend-log test by routing through the proxy - #31689

Merged
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_vertex_passthrough_spendlog_deflake
Jun 30, 2026
Merged

test(pass-through): de-flake vertex spend-log test by routing through the proxy#31689
mateo-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_vertex_passthrough_spendlog_deflake

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

tests/pass_through_tests/test_vertex_ai.py::test_basic_vertex_ai_pass_through_with_spendlog is one of the most flaky tests in the suite; CircleCI's flaky-test insights show it flaking dozens of times in the recent window in proxy_pass_through_endpoint_tests

Linear ticket

N/A

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • 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

Screenshots / Proof of Fix

The root cause is visible in the proxy container logs of a failing proxy_pass_through_endpoint_tests run. Across the whole window the Vertex test was executing, the proxy served all 46 of the test's own GET /global/spend/logs polls but not a single generateContent, and its only upstream forwards were to AssemblyAI and OpenAI

$ grep -oE '"(POST|GET) /[^"]*"' proxy.log | sort | uniq -c | sort -rn
     46 "GET /global/spend/logs?api_key=best-api-key-ever HTTP/1.1"
      7 "GET /assemblyai/v2/transcript/... HTTP/1.1"
      2 "POST /openai/assistants HTTP/1.1"
      ...assemblyai / openai only, no vertex...

$ grep -ciE 'vertex|gemini|generateContent|aiplatform' proxy.log
0

The 46 polls match the test's exact count (1 baseline read plus 5 attempts of 9 polls), so the window covers the full test, yet the billed model.generate_content("hi") calls never reached LiteLLM. The vertexai SDK sent them straight to the public Vertex endpoint, which is why no spend was ever recorded and why re-billing through the SDK could not help

To confirm the rewrite is no longer flaky, the exact CI job that owns this test (proxy_pass_through_endpoint_tests) was rerun until it passed five times in a row on the final commit, with test_basic_vertex_ai_pass_through_with_spendlog green in every run (CircleCI jobs 1956777, 1957800, 1957849, 1957898, 1957899)

Type

✅ Test

Changes

The test configured the vertexai SDK with location="global" and an http api_endpoint pointing at the proxy, then billed generateContent and waited for the global spend aggregate to move. With that configuration the SDK intermittently ignores the endpoint override and calls the public Vertex endpoint directly, so the request bypasses the proxy and no LiteLLM_SpendLogs row is ever written; that bypass, not logging lag, is the flake

This change drives the pass-through over HTTP instead of through the SDK. It mints a Google access token from the same service-account credentials the SDK would use, posts the Vertex-shaped generateContent request straight to /vertex_ai/... on the proxy, and asserts that the specific call's own spend log lands with spend > 0, a gemini model, and a custom_llm_provider of vertex_ai, keyed on the x-litellm-call-id the proxy returns. Because the request now always reaches the proxy, the only residual flake is the best-effort background logging worker occasionally dropping a single event, so the test re-bills a few times and still fails hard if no call is ever tracked. The SDK-based client path stays covered by the sibling jest test (test_vertex_with_spend.test.js)

A small follow-up commit addresses the Greptile review: the get_tracked_spend helper used by the skipped streaming test now reuses the shared LITE_LLM_ENDPOINT constant instead of a hard-coded 0.0.0.0:4000, and drops its needless async since it only performs a blocking requests call

The change is test-only; no production behavior, performance, or contract changes


Note

Low Risk
Test-only changes in test_vertex_ai.py; no production proxy, billing, or API behavior is modified.

Overview
test_basic_vertex_ai_pass_through_with_spendlog no longer bills through the vertexai SDK. It POSTs generateContent to the LiteLLM /vertex_ai/... URL with a Google access token, then polls /spend/logs?request_id= using x-litellm-call-id until that call has spend > 0, gemini model, and vertex_ai provider—retrying up to three billed calls if background logging drops an event.

Shared helpers replace the old async global-spend polling: get_tracked_spend() sums all rows from /global/spend/logs (avoids UTC “today” mismatches) and uses LITE_LLM_ENDPOINT. The skipped streaming test switches to that helper instead of await call_spend_logs_endpoint().

Reviewed by Cursor Bugbot for commit 65e29fc. Bugbot is set up for automated code reviews on this repo. Configure here.

The vertex pass-through spend-log test asserted that a single billed
generateContent call moved the global spend aggregate within a fixed
wait. CI failures show the call returning a valid response with real
usage, yet spend never increasing over a 240s poll.

Pass-through spend logging is best-effort: the success handler is
enqueued on a background worker that can drop or time out an individual
event under load and never retries it, so one billed call occasionally
never reaches LiteLLM_SpendLogs. Waiting longer cannot recover a dropped
event; only re-issuing the call can.

Re-bill the call up to a few times and require at least one to be
tracked, mirroring the sibling jest test that already retries. The test
still fails hard if cost tracking is actually broken, since then every
call records nothing. Also sum spend across all returned days instead of
matching the runner's local 'today', removing a separate UTC-rollover
flake.
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…ect HTTP

The vertexai SDK, configured with location="global" and an http api_endpoint
override, intermittently sends generateContent to the public Vertex endpoint
instead of the proxy. Proxy logs from a failing run show all 46 of the test's
own spend-log polls reaching the proxy while zero generateContent calls did, so
LiteLLM never saw the billed call and no spend was ever recorded; re-billing
through the SDK could not help because every retry bypassed the proxy too.

Issue the pass-through request directly over HTTP so it always hits the proxy,
minting a Google token from the same service-account credentials, then assert
that the specific call's own spend log lands with spend > 0, a gemini model, and
custom_llm_provider vertex_ai. A small best-effort retry covers the rare case
where the background logging worker drops a single event; failing every attempt
still fails hard so the test keeps its teeth if cost tracking breaks.
@mateo-berri mateo-berri changed the title test(pass-through): de-flake vertex spend-log assertion by re-billing test(pass-through): de-flake vertex spend-log test by routing through the proxy Jun 30, 2026
@mateo-berri
mateo-berri marked this pull request as ready for review June 30, 2026 20:11
@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Rewrites test_basic_vertex_ai_pass_through_with_spendlog to drive the Vertex pass-through over a direct HTTP request instead of the vertexai SDK, eliminating the root cause of the flake (the SDK silently bypassing the proxy endpoint override). The test now asserts on a per-call spend log keyed by x-litellm-call-id and retries up to three times to tolerate the background logging worker dropping a single event.

  • Replaces the global-spend-delta assertion with a precise per-call spend log lookup using x-litellm-call-id, reducing false negatives from unrelated concurrent traffic.
  • Extracts get_tracked_spend, _vertex_access_token, _spend_log_for_request, and shared constants (LITE_LLM_ENDPOINT, SPEND_LOG_API_KEY) to clean up the previously tangled helpers and fix the async/hardcoded-address issues flagged in earlier review rounds.
  • Updates the skipped streaming test to use the shared get_tracked_spend helper for consistency.

Confidence Score: 5/5

Test-only change with no production code modified; the rewrite is strictly additive and the previous review comments have both been addressed.

The change is confined to a single integration test file. The root cause of the flake is well-documented in the PR, the fix is mechanically sound (direct HTTP avoids the SDK endpoint-override bug), the per-call x-litellm-call-id assertion is stronger than the previous global-spend-delta check, and earlier review concerns about the async helper and hard-coded endpoint have been resolved.

No files require special attention.

Important Files Changed

Filename Overview
tests/pass_through_tests/test_vertex_ai.py Rewrites the spend-log test to use direct HTTP instead of the vertexai SDK, adding precise per-call assertion via x-litellm-call-id and fixing the previously flagged async/hardcoded-endpoint issues in the helper functions.

Reviews (2): Last reviewed commit: "test(pass-through): reuse LITE_LLM_ENDPO..." | Re-trigger Greptile

Comment thread tests/pass_through_tests/test_vertex_ai.py Outdated
Comment thread tests/pass_through_tests/test_vertex_ai.py Outdated
@codspeed-hq

codspeed-hq Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing litellm_vertex_passthrough_spendlog_deflake (65e29fc) with litellm_internal_staging (8beb68a)

Open in CodSpeed

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai


Generated by Claude Code

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 65e29fc. Configure here.

@mateo-berri
mateo-berri merged commit a7d8c6f into litellm_internal_staging Jun 30, 2026
128 checks passed
@mateo-berri
mateo-berri deleted the litellm_vertex_passthrough_spendlog_deflake branch June 30, 2026 22:27
mubashir1osmani added a commit that referenced this pull request Jul 1, 2026
Port the de-flake of the SDK-based vertex spend test (#31689) into the
tests/e2e/llm_translation harness. The vertexai SDK intermittently ignored the
proxy api_endpoint override and billed Vertex directly, so the request never
reached LiteLLM and no spend was logged; driving native generateContent over the
shared transport always reaches the proxy, which the harness already guarantees.

Credentials stay on the proxy, the same way the gemini and anthropic passthrough
tests work. The gemini-2.5-flash-vertex deployment is marked use_in_pass_through,
so the proxy registers its service account for the /vertex_ai route and mints the
Vertex token itself; the test sends only its litellm virtual key in
x-litellm-api-key and no upstream bearer, targeting that deployment's region. The
Vertex credential lives in one place, the proxy's secret, and the test holds
nothing and never mints a token.

Asserts both that the forward succeeds and that a costed SpendLogs row lands
(vertex_ai provider, a gemini model, spend > 0, call_type pass_through_endpoint),
correlated by the x-litellm-call-id header.
mubashir1osmani added a commit that referenced this pull request Jul 1, 2026
Port the de-flake of the SDK-based vertex spend test (#31689) into the
tests/e2e/llm_translation harness. The vertexai SDK intermittently ignored the
proxy api_endpoint override and billed Vertex directly, so the request never
reached LiteLLM and no spend was logged; driving native generateContent over the
shared transport always reaches the proxy, which the harness already guarantees.

The vertex deployment is added at runtime through /model/new with
use_in_pass_through rather than declared in the gateway config, and deleted on
teardown. That registers the deployment's service account for the /vertex_ai
route, so the passthrough call sends only its litellm virtual key in
x-litellm-api-key and no upstream bearer, and the proxy mints the Vertex token
itself. The credential is the one the proxy already holds, read from the same
VERTEXAI_CREDENTIALS/VERTEXAI_PROJECT env; the test never mints a token.

Asserts both that the forward succeeds and that a costed SpendLogs row lands
(vertex_ai provider, a gemini model, spend > 0, call_type pass_through_endpoint),
correlated by the x-litellm-call-id header.
duanhongyi pushed a commit to duanhongyi/litellm that referenced this pull request Jul 2, 2026
… the proxy (BerriAI#31689)

* test(pass-through): de-flake vertex spend-log assertion by re-billing

The vertex pass-through spend-log test asserted that a single billed
generateContent call moved the global spend aggregate within a fixed
wait. CI failures show the call returning a valid response with real
usage, yet spend never increasing over a 240s poll.

Pass-through spend logging is best-effort: the success handler is
enqueued on a background worker that can drop or time out an individual
event under load and never retries it, so one billed call occasionally
never reaches LiteLLM_SpendLogs. Waiting longer cannot recover a dropped
event; only re-issuing the call can.

Re-bill the call up to a few times and require at least one to be
tracked, mirroring the sibling jest test that already retries. The test
still fails hard if cost tracking is actually broken, since then every
call records nothing. Also sum spend across all returned days instead of
matching the runner's local 'today', removing a separate UTC-rollover
flake.

* test(pass-through): route vertex spend-log test through proxy via direct HTTP

The vertexai SDK, configured with location="global" and an http api_endpoint
override, intermittently sends generateContent to the public Vertex endpoint
instead of the proxy. Proxy logs from a failing run show all 46 of the test's
own spend-log polls reaching the proxy while zero generateContent calls did, so
LiteLLM never saw the billed call and no spend was ever recorded; re-billing
through the SDK could not help because every retry bypassed the proxy too.

Issue the pass-through request directly over HTTP so it always hits the proxy,
minting a Google token from the same service-account credentials, then assert
that the specific call's own spend log lands with spend > 0, a gemini model, and
custom_llm_provider vertex_ai. A small best-effort retry covers the rare case
where the background logging worker drops a single event; failing every attempt
still fails hard so the test keeps its teeth if cost tracking breaks.

* test(pass-through): reuse LITE_LLM_ENDPOINT and drop needless async in get_tracked_spend
mubashir1osmani added a commit that referenced this pull request Jul 3, 2026
* test(e2e): add vertex_ai passthrough spend-log coverage

Port the de-flake of the SDK-based vertex spend test (#31689) into the
tests/e2e/llm_translation harness. The vertexai SDK intermittently ignored the
proxy api_endpoint override and billed Vertex directly, so the request never
reached LiteLLM and no spend was logged; driving native generateContent over the
shared transport always reaches the proxy, which the harness already guarantees.

The vertex deployment is added at runtime through /model/new with
use_in_pass_through rather than declared in the gateway config, and deleted on
teardown. That registers the deployment's service account for the /vertex_ai
route, so the passthrough call sends only its litellm virtual key in
x-litellm-api-key and no upstream bearer, and the proxy mints the Vertex token
itself. The credential is the one the proxy already holds, read from the same
VERTEXAI_CREDENTIALS/VERTEXAI_PROJECT env; the test never mints a token.

Asserts both that the forward succeeds and that a costed SpendLogs row lands
(vertex_ai provider, a gemini model, spend > 0, call_type pass_through_endpoint),
correlated by the x-litellm-call-id header.

* Update tests/e2e/llm_translation/test_vertex_passthrough_e2e.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Update tests/e2e/llm_translation/test_vertex_passthrough_e2e.py

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
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