{"record":{"id":"d8877341ca4afbcd","repo":"BerriAI/litellm","slug":"project-id-is-required","errorCode":null,"errorMessage":"project_id is required","messagePattern":"project_id is required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py","lineNumber":555,"sourceCode":"\n        # ADD METADATA FIELDS\n        for field in LiteLLM_ManagementEndpoint_MetadataFields_Premium:\n            if getattr(data, field, None) is not None:\n                _set_object_metadata_field(\n                    object_data=data,\n                    field_name=field,\n                    value=getattr(data, field),\n                )\n                delattr(data, field)\n\n        if prisma_client is None:\n            raise HTTPException(\n                status_code=500,\n                detail={\"error\": CommonProxyErrors.db_not_connected_error.value},\n            )\n\n        if data.project_id is None:\n            raise HTTPException(\n                status_code=400,\n                detail={\"error\": \"project_id is required\"},\n            )\n\n        # Fetch existing project\n        existing_project: (\n            prisma_models.LiteLLM_ProjectTable | None\n        ) = await prisma_client.db.litellm_projecttable.find_unique(where={\"project_id\": data.project_id})\n\n        if existing_project is None:\n            raise ProxyException(\n                message=f\"Project not found, project_id={data.project_id}\",\n                type=\"not_found\",\n                code=404,\n                param=\"project_id\",\n            )\n\n        # Permission to *edit* the project must be evaluated against the","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/enterprise/litellm_enterprise/proxy/management_endpoints/project_endpoints.py#L537-L573","documentation":"PUT /project/update requires project_id to identify the record to modify; the field is optional on the Pydantic model, so a missing/null value is caught explicitly and rejected with HTTP 400 before the database fetch. Unlike creation, no id is ever generated on update.","triggerScenarios":"PUT /project/update with a body that omits project_id or sends it as null, e.g. only {\"max_budget\": 100}.","commonSituations":"Reusing a creation payload template for updates, frontend form not binding the id field, or stripping ids during JSON sanitization.","solutions":["Include the existing project_id in the update payload","If you do not know the id, list projects first (e.g. GET /project/list) to find it","Distinguish create vs update flows in client code: update always needs the id"],"exampleFix":"// before\n{\"max_budget\": 100}\n// after\n{\"project_id\": \"project-123\", \"max_budget\": 100}","handlingStrategy":"type-guard","validationCode":"if not payload.get('project_id'):\n    raise ValueError('PUT /project/update requires project_id; fetch it via GET /project/list')","typeGuard":"const isUpdatePayload = (p): p is { project_id: string } =>\n  typeof p.project_id === 'string' && p.project_id.length > 0;","tryCatchPattern":null,"preventionTips":["Use distinct types/functions for create vs update payloads in client code","Bind update forms to the id fetched from list endpoints, never free-text input"],"tags":["litellm","validation","request-payload","http-400"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}