BerriAI/litellm · error · HTTPException

project_id is required

Error message

project_id is required

What it means

Update requires the client to name which project to change. Unlike create (which can auto-generate an id), update has no default: a payload where project_id is None — missing, null, or empty — is rejected with 400 immediately after the DB check, before any row is fetched.

Solutions

  1. Include project_id in the update payload — copy it from GET /project/list or the create response
  2. If using a serialization layer, disable exclude_none for this call so set ids are not dropped
  3. Log the outgoing payload at DEBUG before sending to catch silently-dropped required fields

Example fix

# before (400: project_id is required)
httpx.post(base + '/project/update', headers=hdr, json={'project_name': 'new-name'})

# after
httpx.post(base + '/project/update', headers=hdr, json={'project_id': 'p1', 'project_name': 'new-name'})
Defensive patterns

Strategy: validation

Validate before calling

def validate_update_payload(payload: dict) -> None:
    pid = payload.get('project_id')
    if not isinstance(pid, str) or not pid.strip():
        raise ValueError('/project/update requires a non-empty string project_id')

validate_update_payload(payload)
httpx.post(base + '/project/update', headers=hdr, json=payload)

Type guard

def is_valid_update_payload(p: dict) -> bool:
    return isinstance(p, dict) and isinstance(p.get('project_id'), str) and len(p['project_id'].strip()) > 0

Try / catch

except httpx.HTTPStatusError as e:
    if e.response.status_code == 400 and 'project_id is required' in e.response.text:
        raise ValueError('update payload dropped project_id; check serialization (exclude_none)') from None

Prevention

When it happens

Trigger: POST /project/update with project_id absent or explicitly null in the JSON body.

Common situations: Client models serialized with exclude_none=True so the field never reaches the wire; copy-pasting a create payload into an update call; UIs that keep a blank 'current project' field.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

        # ADD METADATA FIELDS
        for field in LiteLLM_ManagementEndpoint_MetadataFields_Premium:
            if getattr(data, field, None) is not None:
                _set_object_metadata_field(
                    object_data=data,
                    field_name=field,
                    value=getattr(data, field),
                )
                delattr(data, field)

        if prisma_client is None:
            raise HTTPException(
                status_code=500,
                detail={"error": CommonProxyErrors.db_not_connected_error.value},
            )

        if data.project_id is None:
            raise HTTPException(
                status_code=400,
                detail={"error": "project_id is required"},
            )

        # Fetch existing project
        existing_project: (
            prisma_models.LiteLLM_ProjectTable | None
        ) = await _project_table(prisma_client).find_unique(where={"project_id": data.project_id})

        if existing_project is None:
            raise ProxyException(
                message=f"Project not found, project_id={data.project_id}",
                type="not_found",
                code=404,
                param="project_id",
            )

        # Permission to *edit* the project must be evaluated against the

View on GitHub (pinned to 77b7c6c40c)