BerriAI/litellm · error · BadRequestError

{custom_llm_provider.capitalize()}Exception BadRequestError

Error message

{custom_llm_provider.capitalize()}Exception BadRequestError - {error_str}

What it means

In _map_vertex_exception, if the error string contains '403' (and no earlier rule matched), LiteLLM raises a BadRequestError with a synthetic 403 response. Vertex AI 403 responses mean the caller's credentials are authenticated but not authorized: the principal lacks the Vertex AI Service Agent role, the API is disabled, or the resource lives in another project. Note LiteLLM's historical quirk: despite the 403 status it maps to BadRequestError here rather than PermissionDeniedError (which is only used for a literal status_code == 403 later in the chain).

Source

Thrown at litellm/litellm_core_utils/exception_mapping_utils.py:1131

            message=f"litellm.InternalServerError: {custom_llm_provider}Exception - {error_str}",
            model=model,
            llm_provider=custom_llm_provider,
            response=httpx.Response(
                status_code=500,
                content=str(original_exception),
                request=httpx.Request(method="completion", url="https://github.com/BerriAI/litellm"),
            ),
            litellm_debug_info=extra_information,
        )
    elif "API key not valid." in error_str:
        raise AuthenticationError(
            message=f"{custom_llm_provider.capitalize()}Exception - {error_str}",
            model=model,
            llm_provider=custom_llm_provider,
            litellm_debug_info=extra_information,
        )
    elif "403" in error_str:
        raise BadRequestError(
            message=f"{custom_llm_provider.capitalize()}Exception BadRequestError - {error_str}",
            model=model,
            llm_provider=custom_llm_provider,
            response=httpx.Response(
                status_code=403,
                request=httpx.Request(
                    method="POST",
                    url=" https://cloud.google.com/vertex-ai/",
                ),
            ),
            litellm_debug_info=extra_information,
        )
    elif (
        "The response was blocked." in error_str
        or "Output blocked by content filtering policy" in error_str  # anthropic on vertex ai
    ):
        raise ContentPolicyViolationError(
            message=f"{custom_llm_provider.capitalize()}Exception ContentPolicyViolationError - {error_str}",

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. Grant the calling principal roles/aiplatform.user (or roles/aiplatform.serviceAgent) on the project
  2. Enable aiplatform.googleapis.com in the project that owns the model deployment
  3. Verify the model is supported in vertex_location (e.g. some models only in us-central1/europe-west4) and switch location
  4. Check the raw error text for which permission was denied, and inspect VPC-SC / org-policy constraints if present

Example fix

# before
resp = completion(
    model="vertex_ai/gemini-1.5-pro",
    messages=[...],
    vertex_project="shared-models-proj",
)
# ...Exception BadRequestError - 403 ... PERMISSION_DENIED

# after: give the SA access in the owning project
# gcloud projects add-iam-policy-binding shared-models-proj \
#   --member='serviceAccount:caller@proj.iam.gserviceaccount.com' \
#   --role='roles/aiplatform.user'
resp = completion(
    model="vertex_ai/gemini-1.5-pro",
    messages=[...],
    vertex_project="shared-models-proj",
    vertex_location="us-central1",
)
Defensive patterns

Strategy: try-catch

Validate before calling

import subprocess

def has_aiplatform_role(project: str, member: str) -> bool:
    out = subprocess.run(
        ["gcloud", "projects", "get-iam-policy", project, "--flatten",
         "bindings[].members", "--filter", f"bindings.members:{member}",
         "--format", "value(bindings.role)"],
        capture_output=True, text=True,
    )
    return "roles/aiplatform.user" in out.stdout

Try / catch

import litellm

try:
    resp = litellm.completion(model="vertex_ai/gemini-1.5-pro", messages=msgs)
except litellm.BadRequestError as e:
    if "403" in str(e):
        raise PermissionError(
            "Vertex 403: check roles/aiplatform.user, API enabled, region"
        ) from e
    raise

Prevention

When it happens

Trigger: A vertex_ai completion where the underlying google.cloud exception string contains '403': caller lacks roles/aiplatform.user, the Vertex AI API is disabled on the project, VPC-SC or org policy blocks the endpoint, or the model is not available in the configured region.

Common situations: Service account has only Viewer role; using a shared model endpoint in a different GCP project without cross-project service usage permission; regional restriction (model not enabled in vertex_location); org policy / VPC Service Controls perimeter rejection.

Related errors


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