mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
fix: normalize alert-email configs at merge boundary
_merge_budget_alert_email_configs previously called list() directly on each threshold's value, which raised TypeError on null YAML values and silently split bare strings into single characters. Both are reachable from user- supplied global config and per-key metadata, so the crash could fire on every authenticated request once the metadata was in place. Route both inputs through a _normalize_alert_emails helper that delegates to the existing _parse_email_list parser (lazy-imported, matching the enterprise import pattern used elsewhere in proxy/). The merge body keeps its tight Dict[str, List[str]] contract.
This commit is contained in:
parent
09a524a351
commit
8b86a3b041
1 changed files with 24 additions and 7 deletions
|
|
@ -2946,24 +2946,41 @@ async def _virtual_key_soft_budget_check(
|
|||
)
|
||||
|
||||
|
||||
def _normalize_alert_emails(
|
||||
cfg: Optional[Dict[str, Any]],
|
||||
) -> Dict[str, List[str]]:
|
||||
"""Coerce user-supplied threshold→recipients mapping to Dict[str, List[str]].
|
||||
|
||||
Values may legitimately arrive as list, comma-separated string, or None
|
||||
from YAML/metadata; _parse_email_list tolerates all three.
|
||||
"""
|
||||
if not cfg:
|
||||
return {}
|
||||
from litellm_enterprise.enterprise_callbacks.send_emails.base_email import (
|
||||
_parse_email_list,
|
||||
)
|
||||
|
||||
return {k: _parse_email_list(v) for k, v in cfg.items()}
|
||||
|
||||
|
||||
def _merge_budget_alert_email_configs(
|
||||
global_cfg: Optional[Dict[str, List[str]]],
|
||||
per_key_cfg: Optional[Dict[str, List[str]]],
|
||||
global_cfg: Optional[Dict[str, Any]],
|
||||
per_key_cfg: Optional[Dict[str, Any]],
|
||||
) -> Optional[Dict[str, List[str]]]:
|
||||
"""
|
||||
Per-threshold additive merge: each threshold's recipient list is the union
|
||||
of global + per-key entries (deduped, global-first ordering). Missing
|
||||
thresholds on one side are inherited from the other.
|
||||
"""
|
||||
global_cfg = global_cfg or {}
|
||||
per_key_cfg = per_key_cfg or {}
|
||||
if not global_cfg and not per_key_cfg:
|
||||
global_cfg_normalized = _normalize_alert_emails(global_cfg)
|
||||
per_key_cfg_normalized = _normalize_alert_emails(per_key_cfg)
|
||||
if not global_cfg_normalized and not per_key_cfg_normalized:
|
||||
return None
|
||||
thresholds = set(global_cfg) | set(per_key_cfg)
|
||||
thresholds = set(global_cfg_normalized) | set(per_key_cfg_normalized)
|
||||
return {
|
||||
t: list(
|
||||
dict.fromkeys(
|
||||
list(global_cfg.get(t, [])) + list(per_key_cfg.get(t, []))
|
||||
global_cfg_normalized.get(t, []) + per_key_cfg_normalized.get(t, [])
|
||||
)
|
||||
)
|
||||
for t in thresholds
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue