BerriAI/litellm · error · OrganizationNotFoundError

Organization doesn't exist in db. Organization={org_id}. Cre

Error message

Organization doesn't exist in db. Organization={org_id}. Create organization via `/organization/new` call.

What it means

OrganizationNotFoundError raised when the by-id organization query returns None: the row is confirmed absent from LiteLLM_OrganizationTable. Unlike the generic 500 wrapper, this exception deliberately distinguishes 'org really does not exist' from operational failures (which now propagate raw), so callers can treat absence as 'no org restriction' without swallowing DB outages. It subclasses Exception, so existing except Exception handlers keep working.

Source

Thrown at litellm/proxy/auth/auth_checks.py:3324

    if deserialized_org is not None:
        return deserialized_org
    # else, check db
    try:
        query_kwargs: Final[dict[str, Mapping[str, object]]] = {"where": {"organization_id": org_id}}
        if include_budget_table:
            query_kwargs["include"] = {"litellm_budget_table": True}

        response: Final = await _model_dump_table(OrganizationRepository(prisma_client)).find_unique(**query_kwargs)
    except Exception:
        # An operational failure (DB down, timeout, cache fault) is NOT the same fact as a confirmed
        # missing row, and relabelling it as "doesn't exist" made every caller unable to tell them
        # apart — a caller that treats absence as "this org places no restriction" then drops a real
        # org ceiling during an outage. Propagate the real error; callers that already catch
        # Exception are unaffected.
        raise

    if response is None:
        raise OrganizationNotFoundError(
            f"Organization doesn't exist in db. Organization={org_id}. Create organization via `/organization/new` call."
        )

    _org_obj: Final = LiteLLM_OrganizationTable.model_validate(response.model_dump())
    # Cache the result
    await user_api_key_cache.async_set_cache(
        key=cache_key,
        value=_org_obj,
        model_type=LiteLLM_OrganizationTable,
        ttl=DEFAULT_IN_MEMORY_TTL,
    )

    return _org_obj


async def _get_resources_from_access_groups(
    access_group_ids: Sequence[str],
    resource_field: Literal["access_model_names", "access_mcp_server_ids", "access_agent_ids"],

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Create the organization via POST /organization/new and use the returned organization_id on keys/users
  2. GET /organization/list to confirm the correct organization_id; update the key or user via /key/update or /user/update to point at an existing org
  3. When deleting organizations, also detach or update keys/users/teams that reference the org id

Example fix

curl -X POST http://localhost:4000/organization/new \
  -H "Authorization: Bearer $MASTER_KEY" \
  -d '{"organization_alias": "acme-corp"}'
# attach key to org
curl -X POST http://localhost:4000/key/update \
  -H "Authorization: Bearer $MASTER_KEY" \
  -d '{"key": "sk-...", "organization_id": "org-returned-id"}'
Defensive patterns

Strategy: type-guard

Validate before calling

orgs = (await client.get("/organization/list")).json()
valid_ids = {o["organization_id"] for o in orgs}
assert key_org_id in valid_ids, f"organization {key_org_id} no longer exists"

Type guard

from litellm.proxy.auth.auth_checks import OrganizationNotFoundError

def is_confirmed_missing(exc: Exception) -> bool:
    """True only for a confirmed-absent org, never for an outage."""
    return isinstance(exc, OrganizationNotFoundError)

Try / catch

from litellm.proxy.auth.auth_checks import OrganizationNotFoundError

try:
    org = await get_org_object(org_id, prisma_client, cache)
except OrganizationNotFoundError:
    org = None  # confirmed absent: treat as 'no org restriction' safely
except Exception:
    raise      # operational failure: do NOT treat as absence

Prevention

When it happens

Trigger: A key/user/team references organization_id that has no row — e.g. the org was deleted after keys were issued, the id is a stale JWT claim, or a key was created with a mistyped organization_id.

Common situations: Org deletion without cleaning up member keys/users; environment mismatch (org exists in prod DB, request hits staging); copying key definitions between configs with hardcoded org ids.

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/163cd77cb87dbcd6. Report an issue: GitHub.