{"record":{"id":"c252d000a689dd59","repo":"BerriAI/litellm","slug":"missing-webhook-url-from-environment","errorCode":null,"errorMessage":"Missing webhook_url from environment","messagePattern":"Missing webhook_url from environment","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/SlackAlerting/slack_alerting.py","lineNumber":1061,"sourceCode":"\n    async def model_removed_alert(self, model_name: str):\n        pass\n\n    async def send_webhook_alert(self, webhook_event: WebhookEvent) -> bool:\n        \"\"\"\n        Sends structured alert to webhook, if set.\n\n        Currently only implemented for budget alerts\n\n        Returns -> True if sent, False if not.\n\n        Raises Exception\n            - if WEBHOOK_URL is not set\n        \"\"\"\n\n        webhook_url: Final = os.getenv(\"WEBHOOK_URL\", None)\n        if webhook_url is None:\n            raise Exception(\"Missing webhook_url from environment\")\n\n        payload: Final = webhook_event.model_dump_json()\n        headers: Final = {\"Content-type\": \"application/json\"}\n\n        response: Final = await self.async_http_handler.post(\n            url=webhook_url,\n            headers=headers,\n            data=payload,\n        )\n        if response.status_code == 200:\n            return True\n        else:\n            print(\"Error sending webhook alert. Error=\", response.text)  # noqa: T201\n\n        return False\n\n    async def _check_if_using_premium_email_feature(\n        self,","sourceCodeStart":1043,"sourceCodeEnd":1079,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/SlackAlerting/slack_alerting.py#L1043-L1079","documentation":"SlackAlerting.send_alert_webhook (budget alerts) posts to a generic webhook URL read from the WEBHOOK_URL environment variable; if unset it raises Exception (litellm/integrations/SlackAlerting/slack_alerting.py:1061). Unlike the Slack path, this generic path has no fallback.","triggerScenarios":"Calling the alerting webhook send (budget alert flow) without WEBHOOK_URL exported; running the proxy with alerting configured for budget thresholds but only SLACK_WEBHOOK_URL set.","commonSituations":"Confusion between WEBHOOK_URL (generic webhook alerts) and SLACK_WEBHOOK_URL (Slack alerts); env file not loaded by the proxy process.","solutions":["Export WEBHOOK_URL in the proxy/SDK process environment","If you meant Slack alerts, use SLACK_WEBHOOK_URL and the Slack alerting config instead of the generic webhook path","Verify the env var reaches the process (docker env, systemd Environment=, .env loading)","Guard the call site: skip webhook alerts when the env var is absent"],"exampleFix":"# before\nawait alerting.send_alert_webhook(event)  # WEBHOOK_URL unset\n\n# after\nimport os\nif os.getenv(\"WEBHOOK_URL\"):\n    await alerting.send_alert_webhook(event)","handlingStrategy":"validation","validationCode":"import os\n\ndef webhook_configured() -> bool:\n    return bool(os.getenv(\"WEBHOOK_URL\"))","typeGuard":null,"tryCatchPattern":"try:\n    await alerting.send_alert_webhook(event)\nexcept Exception as e:\n    if \"Missing webhook_url\" in str(e):\n        log.warning(\"skipping webhook alert: WEBHOOK_URL not set\")\n    else:\n        raise","preventionTips":["Set both WEBHOOK_URL and SLACK_WEBHOOK_URL explicitly when configuring alerting","Add env-var presence checks to proxy startup validation","Distinguish generic webhook alerts from Slack alerts in config review"],"tags":["alerting","webhook","environment-variables","slack"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}