BerriAI/litellm · error · Exception

Missing keys={missing_keys} in environment.

Error message

Missing keys={missing_keys} in environment.

What it means

Raised by BraintrustLogger.validate_environment when neither an explicit api_key argument nor the BRAINTRUST_API_KEY environment variable is present. LiteLLM custom logging integrations are constructed at proxy startup, so this usually surfaces as a crash or logged error during initialization of the braintrust callback rather than per-request.

Source

Thrown at litellm/integrations/braintrust_logging.py:67

            "Content-Type": "application/json",
        }
        self._project_id_cache: dict[str, str] = {}  # Cache mapping project names to IDs
        self.global_braintrust_http_handler = get_async_httpx_client(llm_provider=httpxSpecialProvider.LoggingCallback)
        self.global_braintrust_sync_http_handler = HTTPHandler()

    def validate_environment(self, api_key: str | None):
        """
        Expects
        BRAINTRUST_API_KEY

        in the environment
        """
        missing_keys: Final = []
        if api_key is None and os.getenv("BRAINTRUST_API_KEY", None) is None:
            missing_keys.append("BRAINTRUST_API_KEY")

        if len(missing_keys) > 0:
            raise Exception(f"Missing keys={missing_keys} in environment.")

    def get_project_id_sync(self, project_name: str) -> str:
        """
        Get project ID from name, using cache if available.
        If project doesn't exist, creates it.
        """
        if project_name in self._project_id_cache:
            return self._project_id_cache[project_name]

        try:
            response: Final = self.global_braintrust_sync_http_handler.post(
                f"{self.api_base}/project",
                headers=self.headers,
                json={"name": project_name},
            )
            project_dict: Final = response.json()
            project_id: Final = project_dict["id"]
            self._project_id_cache[project_name] = project_id

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Export BRAINTRUST_API_KEY in the environment where the LiteLLM proxy starts: export BRAINTRUST_API_KEY=...
  2. In Docker/K8s, inject it via env or envFrom secret reference so the proxy process sees it
  3. Verify with printenv | grep BRAINTRUST inside the exact container that runs the proxy
  4. If braintrust logging is not intended, remove it from litellm_settings.callbacks / success_callback config

Example fix

# before
litellm_settings:
  callbacks: [braintrust]  # container starts without BRAINTRUST_API_KEY

# after
docker run --env BRAINTRUST_API_KEY=$BRAINTRUST_API_KEY ... ghcr.io/berriai/litellm:latest --config /app/config.yaml
Defensive patterns

Strategy: validation

Validate before calling

import os

def braintrust_ready() -> bool:
    return bool(os.getenv("BRAINTRUST_API_KEY"))

if "braintrust" in callbacks and not braintrust_ready():
    raise RuntimeError("braintrust callback enabled but BRAINTRUST_API_KEY missing")

Try / catch

try:
    logger = BraintrustLogger(...)
except Exception as e:
    if "Missing keys" in str(e):
        raise RuntimeError("Set BRAINTRUST_API_KEY before enabling the braintrust callback") from e
    raise

Prevention

When it happens

Trigger: Enabling the braintrust callback in litellm_settings.callbacks without exporting BRAINTRUST_API_KEY; running in a container/CI where the env var is not injected; passing api_key=None explicitly and relying solely on the environment.

Common situations: Docker/Kubernetes secrets not wired into the proxy container; .env file not loaded in the deployment; env var name typo (e.g. BRAINTRUST_KEY); disabling braintrust locally but the callback config leaked into shared config.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/4fe974558ca41cf2. Report an issue: GitHub.