BerriAI/litellm · error · ValueError
Invalid webhook url value for
Error message
Invalid webhook url value for: {webhook_urls}. Got type={type(_env_value)} What it means
LiteLLM's Slack alerting lets you reference webhook URLs indirectly via the special 'os.environ/ENV_VAR_NAME' syntax in `alert_to_webhook_url`. At startup, `process_slack_alerting_variables` resolves each such reference through `get_secret` and requires the result to be a plain string. If the secret manager returns None (var not set) or a non-string (e.g. a dict from a secret backend), this ValueError is raised. The message reports the offending reference and the actual Python type it got.
Solutions
- Verify the env var actually exists and holds a string: run `echo $SLACK_WEBHOOK_URL_1` (or print `os.getenv('SLACK_WEBHOOK_URL_1')`) in the same environment where litellm runs
- Fix the reference spelling so the name after 'os.environ/' exactly matches the exported variable name
- If the value lives in a secret manager, ensure it is stored as a plain string secret, not a JSON blob/key-value payload
- As a quick unblock, replace the 'os.environ/...' reference with the literal webhook URL to confirm the rest of the alerting config is correct
Example fix
# before
alert_to_webhook_url = {
"llm_api_latency_alert": "os.environ/SLACK_WEBHOOK_URL", # var not exported -> resolves to None
}
litellm.alerting=["slack"]
# after
# export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T000/B000/XXXX first, then
alert_to_webhook_url = {
"llm_api_latency_alert": "os.environ/SLACK_WEBHOOK_URL",
} Defensive patterns
Strategy: validation
Validate before calling
import os
def webhook_refs_ok(alert_to_webhook_url: dict) -> None:
for alert_type, urls in alert_to_webhook_url.items():
candidates = urls if isinstance(urls, list) else [urls]
for u in candidates:
if isinstance(u, str) and u.startswith("os.environ/"):
name = u.split("os.environ/", 1)[1]
val = os.getenv(name)
if not isinstance(val, str) or not val:
raise SystemExit(f"Missing env var {name} for Slack webhook ({alert_type})")
webhook_refs_ok({"llm_api_latency_alert": "os.environ/SLACK_WEBHOOK_URL_1"}) Type guard
def is_resolvable_webhook_ref(ref: str) -> bool:
import os
if not isinstance(ref, str):
return False
if ref.startswith("os.environ/"):
return isinstance(os.getenv(ref.split("os.environ/", 1)[1]), str)
return True Try / catch
try:
litellm.alerting = ["slack"] # triggers webhook resolution
except ValueError as e:
if "Invalid webhook url value" in str(e):
log.error("Slack webhook env var unresolved", extra={"detail": str(e)})
# degrade: disable alerting rather than crash the app
litellm.alerting = None
else:
raise Prevention
- Add webhook env vars to the same env checklist as API keys in deploy scripts
- Use fail-fast startup checks for every 'os.environ/...' reference in alerting config
- Prefer literal webhook URLs in dev environments to isolate secret-resolution issues
When it happens
Trigger: Calling `litellm.alerting()` or constructing SlackAlerting with `alert_to_webhook_url={'llm_api_latency_alert': 'os.environ/SLACK_WEBHOOK_URL_1'}` when SLACK_WEBHOOK_URL_1 is unset, or when the secret is stored in a connected secret manager (e.g. AWS/Kubernetes) under a non-string value. Also triggered with a list of URLs where one element is an 'os.environ/...' reference that resolves to None.
Common situations: Typo in the env var name after 'os.environ/'; forgetting to export the var in the deployment shell/docker-compose/k8s manifest; secret manager returning a JSON object instead of a raw string; CI environments where the webhook var is only set in one job.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- auth_error
- Invalid webhook url value for
- Missing SLACK_WEBHOOK_URL from environment
- Missing webhook_url from environment
- API key is required
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/6f1e4bcec05f6184.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/integrations/SlackAlerting/utils.py:48
for alert_type, webhook_urls in alert_to_webhook_url.items():
if isinstance(webhook_urls, list):
_webhook_values: list[str] = []
for webhook_url in webhook_urls:
if "os.environ/" in webhook_url:
_env_value = get_secret(secret_name=webhook_url)
if not isinstance(_env_value, str):
raise ValueError(f"Invalid webhook url value for: {webhook_url}. Got type={type(_env_value)}")
_webhook_values.append(_env_value)
else:
_webhook_values.append(webhook_url)
alert_to_webhook_url[alert_type] = _webhook_values
else:
_webhook_value_str: str = webhook_urls
if "os.environ/" in webhook_urls:
_env_value = get_secret(secret_name=webhook_urls)
if not isinstance(_env_value, str):
raise ValueError(f"Invalid webhook url value for: {webhook_urls}. Got type={type(_env_value)}")
_webhook_value_str = _env_value
else:
_webhook_value_str = webhook_urls
alert_to_webhook_url[alert_type] = _webhook_value_str
return alert_to_webhook_url
async def _add_langfuse_trace_id_to_alert(
request_data: dict | None = None,
) -> str | None:
"""
Returns langfuse trace url
- check:
-> existing_trace_id
-> trace_idView on GitHub (pinned to 77b7c6c40c)