test(e2e): assert provider error shape instead of pinned prose - #37065
Conversation
Both providers reworded the error strings these two cells pinned, so the suite went red without any behavior changing. Anthropic's auth error is now "API key is invalid." rather than "invalid x-api-key", and OpenAI rejects an empty upload with "This model does not support the format you provided.", which names neither "file" nor "audio". Assert the durable shape instead. The otel cell pins the machine-readable authentication_error type plus a non-empty message, and the embedded JSON still has to parse, which is what proves the attribute survived untruncated. The transcription cell pins that the 400 relays the provider's own rejection and is typed as a client input error, so a regression that swallows the provider reason or returns a 500 still fails.
This cell needs the websearch_interception callback and a declared search backend, both listed in its own module docstring. The ephemeral e2e stack ships neither, so the request falls through to the bedrock transformation and takes the by-design 400 that tells you to enable interception. The cell has never been green here: the error path merged about an hour and a half before the cell did, and the last full suite to pass predates the cell entirely. Skip it with the reason recorded so the run reports honestly instead of carrying a permanent red, and unskip once the stack ships the config the docstring already spells out.
…itellm_/nice-wilson-9fbed6
Greptile SummaryThis PR makes two provider-error e2e assertions depend on stable machine-readable error shape rather than mutable provider prose, and skips the Bedrock web-search test because its current stack lacks prerequisites.
Confidence Score: 4/5The PR appears safe to merge, but the unconditional Bedrock test skip should be made configuration-aware so capable environments retain this coverage. The error assertion changes preserve the relevant machine-readable contracts, while the sole non-blocking concern is that an unconditional skip disables Bedrock web-search interception coverage on every target stack. Files Needing Attention: tests/e2e/llm_translation/test_bedrock_web_search_server_tool_e2e.py
|
| Filename | Overview |
|---|---|
| tests/e2e/llm_translation/test_audio_transcriptions_e2e.py | Replaces prose-sensitive empty-upload assertions with status, provider-exception, and machine-readable error-type checks. |
| tests/e2e/llm_translation/test_bedrock_web_search_server_tool_e2e.py | Unconditionally skips the sole Bedrock native web-search interception test, preventing it from running even against configured stacks. |
| tests/e2e/logging/test_otel_trace_e2e.py | Replaces a mutable Anthropic message assertion with provider error-type and non-empty-message validation while retaining parseability and span-fidelity checks. |
Reviews (1): Last reviewed commit: "Merge remote-tracking branch 'origin/lit..." | Re-trigger Greptile
| reason="stage red: environment gap, the e2e stack neither enables the " | ||
| "websearch_interception callback nor declares a search backend, so the request " | ||
| "reaches bedrock's transformation and takes its by-design 400. Unskip once the " | ||
| "ephemeral stack ships the config in this module's docstring." | ||
| ) | ||
| @pytest.mark.covers("llm.messages.bedrock_invoke.web_search_server_tool.nonstream.works") |
There was a problem hiding this comment.
Unconditional skip disables valid coverage
If the target stack has the interception callback and search backend configured, this unconditional marker still skips the sole test for the Bedrock native web-search interception path, leaving that integration untested and its coverage cell reported as skipped.
Rule Used: What: Flag any modifications to existing tests and... (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
91aee78
into
litellm_internal_staging
TLDR
Problem this solves:
How it solves it:
User Flow
Before: an engineer reading the e2e run sees three red cells and cannot tell which ones mean the gateway broke
test_failed_chat_completions_error_span_attributesfailing onassert 'API key is invalid.' == 'invalid x-api-key'test_missing_file_returns_errorfailing because the 400 body says "This model does not support the format you provided." and names neither "file" nor "audio"test_web_search_server_tool_is_servedfailing on a 400 that tells them to enable web search interceptionAfter: the same run is green, and the one cell that cannot run says why
Relevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Captured at
481ab07ca7. Both providers were hit directly, and the transcription case was reproduced through a live proxy on port 4071Anthropic's auth error, which the otel cell used to pin as
invalid x-api-key:The
authentication_errortype the cell now pins is present; the sentence it used to pin is notThe same error as it reaches the span, through litellm's own mapping:
An empty upload through a live proxy, which the transcription cell used to assert named "file" or "audio":
Status is 400,
OpenAIExceptionandinvalid_request_errorare both present, and neither "file" nor "audio" appears anywhere. Running the old and new assertions against these exact payloads: the old ones fail, reproducing the run, and the new ones passThe bedrock cell's upstream error is unchanged and still by design, so its proof is the stack config rather than a request. The ephemeral stack declares
callbacks: [arize_phoenix, datadog, smtp_email, prometheus, otel]and nosearch_toolsblock, so neither prerequisite in that module's docstring is presentType
✅ Test
Caveats
QA runbook
error.message; expectAnthropicExceptionfollowed by the provider's JSON"type": "authentication_error"with a non-empty message, and expectotel.status_descriptionto carry the same untruncated textOpenAIExceptionandinvalid_request_errorwebsearch_interceptioncallback and nosearch_toolsentryweb_search_20250305toolFinal Attestation