diff --git a/litellm/integrations/custom_guardrail.py b/litellm/integrations/custom_guardrail.py index a1c55390db2..2a6ff7f2241 100644 --- a/litellm/integrations/custom_guardrail.py +++ b/litellm/integrations/custom_guardrail.py @@ -923,8 +923,7 @@ class CustomGuardrail(CustomLogger): policy_state[PRE_CALL_EXECUTED_GUARDRAILS_KEY] = [marker] elif marker not in recorded: cast("list[object]", recorded).append(marker) # cast-ok: markers are only compared as strings - requested: Final = next((bucket.get("guardrails") for bucket in buckets if "guardrails" in bucket), None) - if name not in _str_collection(requested): + if not any(name in _str_collection(bucket.get("guardrails")) for bucket in buckets): return named_lists: Final = tuple( cast("list[object]", bucket["applied_guardrails"]) # cast-ok: entries are only compared with names diff --git a/tests/unit/proxy/utils/proxy_logging/test_guardrail_pipeline.py b/tests/unit/proxy/utils/proxy_logging/test_guardrail_pipeline.py index 95a5eb0392b..cf873c6e111 100644 --- a/tests/unit/proxy/utils/proxy_logging/test_guardrail_pipeline.py +++ b/tests/unit/proxy/utils/proxy_logging/test_guardrail_pipeline.py @@ -1846,6 +1846,27 @@ async def test_deployment_hook_names_a_pipeline_step_it_ran_before_any_guardrail assert metadata["applied_guardrails"] == ["second"] +@pytest.mark.asyncio +async def test_deployment_hook_names_a_pipeline_step_requested_only_in_the_other_metadata_bucket() -> None: + guardrail: Final = _PipelineStepGuardrail("second", "pre_call") + kwargs: Final[dict[str, object]] = { + "model": "m", + "messages": [{"role": "user", "content": "hi"}], + "guardrails": ["second"], + "metadata": { + "guardrails": ["first"], + "applied_guardrails": ["first"], + "_pipeline_managed_guardrails": frozenset({"first", "second"}), + }, + "litellm_metadata": {"guardrails": ["second"]}, + } + + await guardrail.async_pre_call_deployment_hook(kwargs=kwargs, call_type=CallTypes.completion) + + assert guardrail.calls == 1 + assert sorted(get_logging_caching_headers(kwargs)["x-litellm-applied-guardrails"].split(",")) == ["first", "second"] + + @pytest.mark.asyncio @pytest.mark.parametrize("named_bucket", ["metadata", "litellm_metadata"]) async def test_deployment_hook_names_a_pipeline_step_next_to_the_steps_already_named_when_both_buckets_exist(