BerriAI/litellm · error · ProxyException
400
400
Error message
Project id = {data.project_id} already exists. Please use a different project id. What it means
When a client supplies an explicit project_id on POST /project/new, LiteLLM checks litellm_projecttable.find_unique for a collision and throws a ProxyException (type bad_request, code 400, param project_id) if the id already exists. Omitting project_id is safe: the server generates a fresh uuid4 that cannot collide in practice.
Source
Thrown at enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py:403
if not has_permission:
raise HTTPException(
status_code=403,
detail={
"error": f"Only admins or team admins can create projects. Your role is {user_api_key_dict.user_role}"
},
)
# Generate project_id if not provided
if data.project_id is None:
data.project_id = str(uuid.uuid4())
else:
# Check if project_id already exists
existing_project = await prisma_client.db.litellm_projecttable.find_unique(
where={"project_id": data.project_id}
)
if existing_project is not None:
raise ProxyException(
message=f"Project id = {data.project_id} already exists. Please use a different project id.",
type="bad_request",
code=400,
param="project_id",
)
# Create budget if not provided
if data.budget_id is None:
data.budget_id = await _create_budget_for_project(
data=data,
user_id=user_api_key_dict.user_id,
litellm_proxy_admin_name=litellm_proxy_admin_name,
prisma_client=prisma_client,
)
## Handle Object Permission - MCP, Vector Stores etc.
object_permission_id = await _set_project_object_permission(
data=data,View on GitHub (pinned to 6c2dcb801b)
Solutions
- Use a different project_id or omit the field and let the server generate a uuid
- Make provisioning scripts check GET /project/info (or catch 400 on project_id) before creating
- On retry-after-timeout, verify the project was not already created before resubmitting the same id
Example fix
# before
curl -X POST .../project/new -d '{"project_id":"project-123","team_id":"t1"}'
# after
curl -X POST .../project/new -d '{"team_id":"t1"}' # server assigns a uuid project_id Defensive patterns
Strategy: try-catch
Validate before calling
try:
await client.get(f'/project/info?project_id={payload["project_id"]}')
raise RuntimeError('project_id already exists; use update instead')
except Exception as e:
if getattr(e, 'status_code', None) != 404:
raise Try / catch
catch (e) {
if (e.status === 400 && /already exists/.test(e.body?.detail?.error ?? e.message ?? '')) {
return client.put('/project/update', body); // idempotent apply: switch to update
}
throw e;
} Prevention
- Make provisioning scripts idempotent: check-then-create, or create without project_id and store the returned uuid
- On request timeouts, verify whether the project was created before retrying with the same id
When it happens
Trigger: POST /project/new with a "project_id" that already exists in the database, e.g. re-running an idempotent provisioning script that specifies project_id after a successful first run.
Common situations: Terraform/Ansible or CI jobs re-applying project creation, retrying a request that actually succeeded server-side, or copying an environment's ids into another without dedup.
Related errors
- soft_budget cannot be negative. Received: {data.soft_budget}
- soft_budget ({data.soft_budget}) must be strictly lower than
- Model '{m}' not in team's allowed models. Team allowed model
- Project max_budget ({data.max_budget}) exceeds team's max_bu
- Project tpm_limit ({data.tpm_limit}) exceeds team's tpm_limi
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/a39b6fcbd028a646.
Report an issue: GitHub.