BerriAI/litellm · warning · Exception

Response from PostHog API status_code

Error message

Response from PostHog API status_code: {response.status_code}, text: {response.text}

What it means

After POSTing a single event to {POSTHOG_API_URL}/batch/, the sync PostHog logger raises this if the final status is anything other than 200. Because response.raise_for_status() runs first, genuine 4xx/5xx surface as httpx.HTTPStatusError — this custom message only fires for statuses raise_for_status tolerates: 201/202/204-style codes and 3xx redirects (httpx does not follow redirects by default). The enclosing except logs it with verbose_logger.exception, so the telemetry event is dropped but the LLM call succeeds.

Solutions

  1. Set POSTHOG_API_URL to the exact region root with https (e.g. https://us.i.posthog.com or https://eu.i.posthog.com), no trailing path
  2. Reproduce with curl -X POST '{url}/batch/' -H 'Content-Type: application/json' -d '<sample batch>' and inspect status plus body
  3. Enable debug logging (set litellm verbose / LITELLM_LOG=DEBUG) to capture the exact status_code/text pair reported in the message
  4. If an intermediary returns non-200 success codes or redirects, exempt the PostHog host from rewriting or follow redirects yourself

Example fix

# before
os.environ['POSTHOG_API_URL'] = 'http://app.posthog.com'  # 301 -> non-200 -> exception in logs

# after
os.environ['POSTHOG_API_URL'] = 'https://us.i.posthog.com'  # matches your project region
Defensive patterns

Strategy: validation

Validate before calling

import httpx, os

url = os.getenv('POSTHOG_API_URL', 'https://us.i.posthog.com').rstrip('/')
resp = httpx.post(f'{url}/batch/', json={'api_key': os.environ['POSTHOG_API_KEY'], 'batch': [], 'historical_migration': False})
if resp.status_code != 200:
    raise RuntimeError(f'PostHog preflight failed: {resp.status_code} {resp.text}')

Prevention

When it happens

Trigger: POSTHOG_API_URL using http:// where the server answers the /batch/ POST with a 301/302 redirect to https; a self-hosted PostHog or an intermediary gateway returning 2xx-but-not-200 (201/202/204); the URL pointing at a non-PostHog service that replies with an odd success code.

Common situations: Region mismatch (us vs eu host), trailing path segments in POSTHOG_API_URL, corporate proxies rewriting responses, PostHog cloud incidents returning unusual statuses.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/1a0c4ba88be5c19d. Report an issue: GitHub.

Appendix: source

Thrown at litellm/integrations/posthog.py:102

                raise Exception("PostHog credentials not found in kwargs")
            event_payload: Final = self.create_posthog_event_payload(kwargs)

            headers: Final = {
                "Content-Type": "application/json",
            }

            payload: Final = self._create_posthog_payload([event_payload], api_key)
            capture_url: Final = f"{api_url.rstrip('/')}/batch/"

            response: Final = self.sync_client.post(
                url=capture_url,
                content=safe_dumps(payload),
                headers=headers,
            )
            response.raise_for_status()

            if response.status_code != 200:
                raise Exception(f"Response from PostHog API status_code: {response.status_code}, text: {response.text}")

            if self.is_mock_mode:
                verbose_logger.debug("[POSTHOG MOCK] Sync event successfully mocked")
            else:
                verbose_logger.debug("PostHog: Sync event successfully sent")

        except Exception as e:
            verbose_logger.exception("PostHog Sync Layer Error - %s", e)

    async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
        try:
            verbose_logger.debug("PostHog: Async logging - Enters logging function for model %s", kwargs)
            self._ensure_async_setup()  # Lazy initialization
            await self._log_async_event(kwargs, response_obj, start_time, end_time)
        except Exception as e:
            verbose_logger.exception("PostHog Layer Error - %s", e)

    async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):

View on GitHub (pinned to 77b7c6c40c)