{"record":{"id":"5079dfe3150ffe5c","repo":"BerriAI/litellm","slug":"maximum-max-batch-size-keys-can-be-updated-at-on-5079df","errorCode":null,"errorMessage":"Maximum {MAX_BATCH_SIZE} keys can be updated at once. Found {len(data.key_ids)} key_ids.","messagePattern":"Maximum (.+?) keys can be updated at once\\. Found (.+?) key_ids\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":3146,"sourceCode":"        user_api_key_cache,\n        user_custom_key_update,\n    )\n\n    if prisma_client is None:\n        raise HTTPException(\n            status_code=500,\n            detail={\"error\": \"Database not connected\"},\n        )\n\n    if not data.team_id:\n        raise HTTPException(\n            status_code=400,\n            detail={\"error\": \"team_id is required\"},\n        )\n\n    MAX_BATCH_SIZE: Final = 500\n    if data.key_ids is not None and len(data.key_ids) > MAX_BATCH_SIZE:\n        raise HTTPException(\n            status_code=400,\n            detail={\n                \"error\": f\"Maximum {MAX_BATCH_SIZE} keys can be updated at once. Found {len(data.key_ids)} key_ids.\"\n            },\n        )\n\n    if data.all_keys_in_team:\n        # \"all\" excludes blocked/expired — bulk refresh shouldn't revive a key an admin disabled.\n        # `blocked` is Boolean? with no default; `/key/generate` writes NULL. Prisma's `NOT`\n        # excludes NULLs, so explicitly OR `false` with `null` to include them.\n        now: Final = datetime.now(timezone.utc)\n        existing_keys = await VerificationTokenRepository(prisma_client).table.find_many(\n            where={\n                \"team_id\": data.team_id,\n                \"AND\": [\n                    {\"OR\": [{\"blocked\": False}, {\"blocked\": None}]},\n                    {\"OR\": [{\"expires\": None}, {\"expires\": {\"gt\": now}}]},\n                ],","sourceCodeStart":3128,"sourceCodeEnd":3164,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L3128-L3164","documentation":"LiteLLM Proxy's bulk team-key update endpoint (POST /team/key/bulk_update) refuses requests whose key_ids array exceeds MAX_BATCH_SIZE (500). The guard runs before any database work, so nothing is modified when it fires. It exists to keep the per-key update loop (one DB write per key) from monopolizing the DB on a single huge request.","triggerScenarios":"POST /team/key/bulk_update with a JSON body containing more than 500 entries in key_ids (e.g. 501+ key hashes/aliases), or a script that fetches the full team key list and blindly sends it back in one request.","commonSituations":"Automation that syncs metadata for every key on a large shared team account; a UI 'select all + update' action over a big team; migrating thousands of keys during onboarding and trying to do it in a single call.","solutions":["Split key_ids into chunks of at most 500 and issue one POST /team/key/bulk_update request per chunk.","If you intended to update every active key in the team, set all_keys_in_team=true instead of listing key_ids — but note that path only works when the team has <=500 keys (it returns a separate error otherwise).","Track which chunk failed from the per-key successful_updates/failed_updates arrays in BulkUpdateKeyResponse and retry only those keys."],"exampleFix":"# before\nresp = client.post(\"/team/key/bulk_update\", json={\"team_id\": tid, \"key_ids\": all_key_ids, \"update_fields\": {...}})\n\n# after\nCHUNK = 500\nfor i in range(0, len(all_key_ids), CHUNK):\n    resp = client.post(\"/team/key/bulk_update\", json={\n        \"team_id\": tid,\n        \"key_ids\": all_key_ids[i:i+CHUNK],\n        \"update_fields\": {...},\n    })\n    resp.raise_for_status()","handlingStrategy":"validation","validationCode":"MAX_BATCH = 500\n\ndef validate_bulk_update_payload(team_id: str, key_ids: list[str]) -> None:\n    if len(key_ids) > MAX_BATCH:\n        raise ValueError(f\"chunk key_ids to <= {MAX_BATCH}; got {len(key_ids)}\")\n\nvalidate_bulk_update_payload(team_id, all_key_ids)","typeGuard":"def is_valid_batch(key_ids: list[str] | None) -> bool:\n    return key_ids is not None and 0 < len(key_ids) <= 500","tryCatchPattern":null,"preventionTips":["Wrap every bulk-update caller in a chunk(key_ids, 500) helper so the limit can never be exceeded.","Cap page sizes when listing keys to keep request payloads aligned with the API's 500-key ceiling.","Log the count before sending; a sudden jump usually means your filter regressed and would have hit the limit."],"tags":["batch-limit","key-management","bulk-update","validation","litellm-proxy"],"backgroundTag":"batch-size-limit-exceeded","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}