BerriAI/litellm · error · Exception

POSTHOG_API_KEY is not set, set 'POSTHOG_API_KEY=<>'

Error message

POSTHOG_API_KEY is not set, set 'POSTHOG_API_KEY=<>'

What it means

litellm's PostHog telemetry callback requires an API key at construction time: PostHogLogger.__init__ raises this Exception when the POSTHOG_API_KEY environment variable is absent (mock-mode setup happens earlier but does not bypass the check). The enclosing handler logs it via verbose_logger.exception and re-raises, so callback initialization fails loudly. Note it only checks for None — an empty string passes init but produces auth failures later at send time.

Solutions

  1. Export POSTHOG_API_KEY in the exact process that runs litellm and verify: python -c "import os; print(repr(os.getenv('POSTHOG_API_KEY')))"
  2. For the proxy, put it in the .env beside the config or inject it as a container secret / environment_variables block
  3. If telemetry is not intended, remove 'posthog' from callbacks entirely
  4. Set POSTHOG_API_URL too if you use EU cloud or self-hosted PostHog (defaults to https://us.i.posthog.com)

Example fix

# before
litellm.callbacks = ['posthog']  # POSTHOG_API_KEY missing -> Exception on first init

# after
import os
if not os.getenv('POSTHOG_API_KEY'):
    raise RuntimeError('Refusing to enable posthog callback: POSTHOG_API_KEY not set')
litellm.callbacks = ['posthog']
Defensive patterns

Strategy: validation

Validate before calling

import os

if not os.getenv('POSTHOG_API_KEY'):
    raise RuntimeError('POSTHOG_API_KEY is required when the posthog callback is enabled')
litellm.callbacks = ['posthog']

Try / catch

try:
    litellm.callbacks = ['posthog']
except Exception as e:
    logger.warning('posthog callback init failed: %s', e)
    litellm.callbacks = []

Prevention

When it happens

Trigger: Registering the posthog callback — litellm.callbacks = ['posthog'] in the SDK or success_callback: ['posthog'] under litellm_settings in proxy config — in a process where POSTHOG_API_KEY was never exported, is set in a different shell/container, or exists only in a .env file that this process does not load.

Common situations: Works locally (var exported in your shell) but fails in Docker/Kubernetes because the secret was not mounted into that container; CI runners without the env; proxy started with a config that references posthog while the deployment env omitted the key.

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


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

Appendix: source

Thrown at litellm/integrations/posthog.py:55

class PostHogLogger(CustomBatchLogger):
    def __init__(self, **kwargs):
        """
        Initializes the PostHog logger, checks if the correct env variables are set

        Required environment variables:
        `POSTHOG_API_KEY` - your PostHog API key
        `POSTHOG_API_URL` - your PostHog API URL (defaults to https://app.posthog.com)
        """
        try:
            verbose_logger.debug("PostHog: in init posthog logger")

            self.is_mock_mode = should_use_posthog_mock()
            if self.is_mock_mode:
                create_mock_posthog_client()
                verbose_logger.debug("[POSTHOG MOCK] PostHog logger initialized in mock mode")

            if os.getenv("POSTHOG_API_KEY", None) is None:
                raise Exception("POSTHOG_API_KEY is not set, set 'POSTHOG_API_KEY=<>'")

            self.async_client = get_async_httpx_client(llm_provider=httpxSpecialProvider.LoggingCallback)
            self.sync_client = _get_httpx_client()

            self.POSTHOG_API_KEY = os.getenv("POSTHOG_API_KEY")
            posthog_api_url: Final = os.getenv("POSTHOG_API_URL", "https://us.i.posthog.com")
            self.posthog_host = posthog_api_url.rstrip("/")
            self.capture_url = f"{self.posthog_host}/batch/"

            self._async_initialized = False
            self.flush_lock = None
            self.log_queue = []

            # Register cleanup handler to flush internal queue on exit
            atexit.register(self._flush_on_exit)

            super().__init__(**kwargs, flush_lock=None, batch_size=POSTHOG_MAX_BATCH_SIZE)

View on GitHub (pinned to 77b7c6c40c)