BerriAI/litellm · error · Exception

Failed to register project: {e.response.text}

Error message

Failed to register project: {e.response.text}

What it means

Exception raised by BraintrustLogger.get_project_id_sync when the POST to {api_base}/project returns an HTTP error status (httpx.HTTPStatusError). The message contains only the raw Braintrust API response body, so the actual status code must be inferred from the body text. This runs on the sync logging path the first time a given project_name is seen (results are cached in _project_id_cache afterwards).

Source

Thrown at litellm/integrations/braintrust_logging.py:88

        """
        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
            return project_id
        except httpx.HTTPStatusError as e:
            raise Exception(f"Failed to register project: {e.response.text}")

    async def get_project_id_async(self, project_name: str) -> str:
        """
        Async version of get_project_id_sync
        """
        if project_name in self._project_id_cache:
            return self._project_id_cache[project_name]

        try:
            response: Final = await self.global_braintrust_http_handler.post(
                f"{self.api_base}/project/register",
                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
            return project_id

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Verify the key: curl -H "Authorization: Bearer $BRAINTRUST_API_KEY" https://api.braintrust.dev/v1/project
  2. Update BRAINTRUST_API_KEY if rotated and restart the proxy (cache is per-process)
  3. Simplify the project name to plain alphanumerics/dashes and retry
  4. Inspect the response body embedded in the message — Braintrust's error JSON names the exact problem
Defensive patterns

Strategy: try-catch

Validate before calling

import httpx, os

def braintrust_key_ok() -> bool:
    try:
        r = httpx.get("https://api.braintrust.dev/v1/project",
                      headers={"Authorization": f"Bearer {os.getenv('BRAINTRUST_API_KEY','')}"},
                      timeout=5)
        return r.status_code < 400
    except httpx.RequestError:
        return False

Try / catch

try:
    project_id = logger.get_project_id_sync(project_name)
except Exception as e:
    # message body distinguishes auth (401) vs payload (4xx); restart clears the per-process cache
    raise RuntimeError(f"braintrust project registration failed: {e}") from e

Prevention

When it happens

Trigger: First sync-logged event for a project when BRAINTRUST_API_KEY is invalid/expired (401), lacks permission (403), or the project name is rejected (4xx). Subsequent calls hit the cache and do not re-raise unless the process restarts.

Common situations: Rotated API keys not updated in the proxy env; org-scoped keys without access to the target project; project names with characters Braintrust rejects; pointing api_base at a wrong/proxied endpoint.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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