This commit is contained in:
ryan-crabbe-berri 2026-10-09 16:17:26 +03:00 • committed by GitHub
commit 5e021354a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 29 additions and 6 deletions

View file

@ -12,7 +12,6 @@ from litellm._logging import verbose_logger, verbose_router_logger
from litellm.constants import ROUTER_FALLBACK_ERROR_DETAIL_MAX_CHARS
from litellm.exceptions import BadRequestError
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
from litellm.litellm_core_utils.sensitive_data_masker import mask_sensitive_structure
from litellm.types.router import CredentialLiteLLMParams
from litellm.types.utils import LlmProviders
@ -103,6 +102,16 @@ def format_no_fallback_group_message(lookup_groups: Sequence[str], fallbacks: Se
)
def _fallback_target_label(target: object) -> str:
match target:
case str():
return target
case {"model": str() as model}:
return model
case _:
return "<unnamed fallback>"
def format_fallback_outcome_message(
model_group: str | None,
fallback_model_group: Sequence[object] | None,
@ -112,7 +121,7 @@ def format_fallback_outcome_message(
lead: Final = f"\n\nLiteLLM: model group '{model_group}' failed with the error above."
if not fallback_model_group:
return f"{lead} No fallback was attempted."
targets: Final = ", ".join(str(mask_sensitive_structure(target)) for target in fallback_model_group)
targets: Final = ", ".join(_fallback_target_label(target) for target in fallback_model_group)
if not fallback_failure_detail:
return f"{lead} Fallback model group(s) configured: {targets}."
return f"{lead} Fallback to {targets} also failed: {fallback_failure_detail}"

View file

@ -405,11 +405,25 @@ async def test_flag_on_masks_fallback_credentials(monkeypatch: pytest.MonkeyPatc
messages=[{"role": "user", "content": "hi"}],
)
msg = excinfo.value.message
# The raw credential must never appear, even though debug exposure is on
assert _FALLBACK_CREDENTIAL not in msg, msg
# The fallback wiring is still shown (masking preserves structure, it does
# not drop the whole message), so the api_key key name survives
assert "api_key" in msg, msg
assert "Fallback to gpt-4o also failed: " in msg, msg
assert "api_key" not in msg, msg
@pytest.mark.asyncio
async def test_flag_on_names_only_the_model_of_client_side_fallback_dicts(monkeypatch: pytest.MonkeyPatch):
monkeypatch.setattr(litellm, "expose_router_debug_in_errors", True)
fallback_prompt = "Patient Jane Doe, SSN 123-45-6789"
router = _router_with_rate_limit_failure()
with pytest.raises(litellm.RateLimitError) as excinfo:
await router.acompletion(
model=_INTERNAL_MODEL_GROUP_NAME,
messages=[{"role": "user", "content": "hi"}],
fallbacks=[{"model": "missing-fallback-model", "messages": [{"role": "user", "content": fallback_prompt}]}],
)
msg = excinfo.value.message
assert "Fallback to missing-fallback-model also failed: " in msg, msg
assert fallback_prompt not in msg, msg
@pytest.mark.asyncio