test(otel): add guardrail list mode regression coverage - #29155
Conversation
Greptile SummaryThis PR fixes a
Confidence Score: 4/5The change is narrowly scoped to the OTEL dedupe helper and carries no risk to the request hot path or auth layer. The normalisation logic correctly handles the reported crash and preserves existing dedupe behaviour for hashable values. The one minor gap is that list and tuple scope parts are collapsed to the same tuple representation, so a caller that mixes the two types for the same logical scope value would get a false dedupe hit — harmless today since the field always arrives as a JSON-decoded list, but silently asymmetric. The
|
| Filename | Overview |
|---|---|
| litellm/integrations/opentelemetry.py | Adds _make_hashable_dedupe_scope_part static method to normalize unhashable scope parts (lists, dicts, sets) before constructing the _emit_once dedupe key, and updates _emit_once to apply it; list and tuple values are collapsed to the same tuple representation. |
| tests/test_litellm/integrations/test_opentelemetry.py | Adds two new unit tests: test_emit_once_handles_list_scope_parts (unit-level dedupe with a list-valued mode) and test_create_guardrail_span_handles_list_guardrail_mode (integration-level span emission). Both use only in-memory exporters — no real network calls. |
Reviews (1): Last reviewed commit: "Fix OTEL guardrail mode dedupe" | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
We’re also affected by this issue in production. We can consistently reproduce the error when using OpenTelemetry callbacks together with guardrails configured with multiple modes:
This results in:
After reviewing the proposed changes, #29155 appears to address our scenario by making the OTEL deduplication key generation resilient to unhashable values, including lists. This issue is currently blocking our OpenTelemetry observability rollout. We would appreciate getting this PR reviewed and merged. If helpful, we can also help validate the fix in a production-like environment. |
8158269 to
e3621d3
Compare
I believe #31262 solves the same issue! |
|
Closing as superseded by #31262, which merged the underlying OTEL _emit_once hashable-scope fix for list-valued guardrail_mode and broader regression coverage. Thanks! |
What
Adds regression coverage for OpenTelemetry guardrail span dedupe when guardrail metadata contains list-valued modes, e.g.
mode: ["pre_call", "post_call"].Refs #28486.
Context
The current
litellm_internal_stagingbranch already contains the implementation that normalizes_emit_oncescope parts via_freeze_for_dedupe. After rebasing to resolve conflicts, this PR is intentionally test-only.Changes
_emit_oncecoverage for list-valued scope parts_create_guardrail_spancoverage proving list-valuedguardrail_modeemits exactly one guardrail span across repeated lifecycle callsTests
uv run --no-sync pytest tests/test_litellm/integrations/test_opentelemetry.py::TestOpenTelemetrySpanDedupe -quv run --no-sync black --check tests/test_litellm/integrations/test_opentelemetry.pygit diff --check