BerriAI/litellm · error · ProxyException

404

404

Error message

Team not found, team_id={team_id}

What it means

_validate_team_exists is the first validation step of the project endpoints: it does find_unique on LiteLLM_TeamTable by team_id and raises ProxyException (type=not_found, code=404, param=team_id) when the row is absent, before any project mutation happens.

Source

Thrown at enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py:114

        team = await _team_table(prisma_client).find_unique(where={"team_id": team_id})

    if team and team.admins:
        return user_api_key_dict.user_id in team.admins

    return False


async def _validate_team_exists(
    team_id: str,
    prisma_client: PrismaClient,
) -> "prisma_models.LiteLLM_TeamTable":
    """Validate that a team exists. Returns the team row."""
    team = await _team_table(prisma_client).find_unique(
        where={"team_id": team_id},
    )

    if team is None:
        raise ProxyException(
            message=f"Team not found, team_id={team_id}",
            type="not_found",
            code=404,
            param="team_id",
        )

    return team


def _check_team_project_limits(
    team_object: LiteLLM_TeamTable,
    data: NewProjectRequest | UpdateProjectRequest,
) -> None:
    """
    Check that project limits respect its parent Team's limits.

    Mirrors _check_org_team_limits() from team_endpoints.py.

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. List teams via GET /team/list and copy the exact team_id
  2. Create the team first via POST /team/new if it should exist
  3. Confirm you are authenticated to the intended proxy/DB (staging vs prod)

Example fix

# before
curl -X POST http://0.0.0.0:4000/project/new -d '{"team_id": "team-123", "project_alias": "p1"}'

# after: use a real team_id from GET /team/list
curl -X POST http://0.0.0.0:4000/project/new -d '{"team_id": "<id-from-/team/list>", "project_alias": "p1"}'
Defensive patterns

Strategy: validation

Validate before calling

teams = await get("/team/list")
team_ids = {t["team_id"] for t in teams}
if data["team_id"] not in team_ids:
    raise ValueError(f"team {data['team_id']} does not exist; pick from {sorted(team_ids)}")
await post("/project/new", json=data)

Try / catch

try:
    await post("/project/new", json=data)
except HTTPStatusError as e:
    if e.response.status_code == 404 and "Team not found" in e.response.text:
        create_team_then_retry()  # or fix the id
    raise

Prevention

When it happens

Trigger: POST /project/new, /project/update, /project/info or /project/delete with a team_id that does not exist — typo, deleted team, or wrong database/environment.

Common situations: Hardcoded team ids copied from another deployment; the team was deleted by an admin mid-workflow; scripts pointed at a fresh database.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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