{"record":{"id":"d2a3e87cd43ef4fc","repo":"BerriAI/litellm","slug":"you-must-have-an-enterprise-license-to-set-model-m","errorCode":null,"errorMessage":"You must have an enterprise license to set model_max_budget. You must be a LiteLLM Enterprise user to use this feature. If you have a license please set `LITELLM_LICENSE` in your env. Get a 7 day trial key here: https://www.litellm.ai/enterprise#trial. \nPricing: https://www.litellm.ai/#pricing","messagePattern":"You must have an enterprise license to set model_max_budget\\. You must be a LiteLLM Enterprise user to use this feature\\. If you have a license please set `LITELLM_LICENSE` in your env\\. Get a 7 day trial key here: https://www\\.litellm\\.ai/enterprise#trial\\. \nPricing: https://www\\.litellm\\.ai/#pricing","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"litellm/proxy/management_endpoints/key_management_endpoints.py","lineNumber":6696,"sourceCode":"\n\ndef validate_model_max_budget(model_max_budget: dict | None) -> None:\n    \"\"\"\n    Validate the model_max_budget is GenericBudgetConfigType + enforce user has an enterprise license\n\n    Raises:\n        Exception: If model_max_budget is not a valid GenericBudgetConfigType\n    \"\"\"\n    try:\n        if model_max_budget is None:\n            return\n        if len(model_max_budget) == 0:\n            return\n        if model_max_budget is not None:\n            from litellm.proxy.proxy_server import CommonProxyErrors, premium_user\n\n            if premium_user is not True:\n                raise ValueError(\n                    f\"You must have an enterprise license to set model_max_budget. {CommonProxyErrors.not_premium_user.value}\"\n                )\n            for _model, _budget_info in model_max_budget.items():\n                assert isinstance(_model, str)\n\n                # Normalize to dict (Pydantic may already parse nested values as BudgetConfig)\n                _info = _budget_info.model_dump() if hasattr(_budget_info, \"model_dump\") else dict(_budget_info)\n                # /CRUD endpoints can pass budget_limit as a string, so we need to convert it to a float\n                if \"budget_limit\" in _info:\n                    _info[\"budget_limit\"] = float(_info[\"budget_limit\"])\n                BudgetConfig(**_info)\n    except Exception as e:\n        raise ValueError(\n            f\"Invalid model_max_budget: {e}. Example of valid model_max_budget: https://docs.litellm.ai/docs/proxy/users\"\n        )\n","sourceCodeStart":6678,"sourceCodeEnd":6712,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/key_management_endpoints.py#L6678-L6712","documentation":"model_max_budget (per-model budget limits on a key) is an enterprise feature: when a non-empty model_max_budget dict is supplied and the proxy did not verify an enterprise license (premium_user is not True), validate_model_max_budget raises. In practice this ValueError is immediately re-wrapped by the function's own except, so clients see 'Invalid model_max_budget: You must have an enterprise license...'. The check runs before the BudgetConfig structural validation.","triggerScenarios":"POST /key/generate or CRUD key endpoints with 'model_max_budget': {'gpt-4o': {'budget_limit': 5, 'budget_duration': '1d'}} on a proxy with no or expired LITELLM_LICENSE; license env var set but invalid so premium_user stayed False.","commonSituations":"Copying enterprise-tier config examples into a community deployment; license key not propagated to Docker containers or Kubernetes secrets; trial license expiring between deploys.","solutions":["Obtain a license (7-day trial at litellm.ai/enterprise#trial) and export LITELLM_LICENSE in the proxy's environment, then restart","Verify the license is loaded (premium_user) via startup logs or the admin UI before retrying","If you do not want the feature, remove model_max_budget from the request and use the standard max_budget field instead","In Kubernetes, check the secret is actually mounted into the proxy pod's env"],"exampleFix":"# before\nawait client.post('/key/generate', json={\n    'model_max_budget': {'gpt-4o': {'budget_limit': 5, 'budget_duration': '1d'}}   # enterprise gate trips\n})\n# after (option 1: license)\n$ export LITELLM_LICENSE='<your-enterprise-key>'   # then restart the proxy\n# after (option 2: community)\nawait client.post('/key/generate', json={'max_budget': 5})   # single overall budget, no license needed","handlingStrategy":"fallback","validationCode":"import os\n\ndef enterprise_enabled() -> bool:\n    return bool(os.getenv('LITELLM_LICENSE'))\n\ndef key_budget_payload(max_overall: float, per_model: dict | None) -> dict:\n    if per_model and not enterprise_enabled():\n        return {'max_budget': max_overall}          # graceful downgrade: no per-model budgets\n    return {'max_budget': max_overall, 'model_max_budget': per_model}","typeGuard":null,"tryCatchPattern":"try:\n    await client.post('/key/generate', json={'model_max_budget': mm, ...})\nexcept Exception as e:\n    if 'enterprise license' in str(e):\n        mm.pop('model_max_budget', None)            # retry without the enterprise field\n        await client.post('/key/generate', json={**payload_without_mm})\n    else:\n        raise","preventionTips":["Gate enterprise-only fields behind a license check in your provisioning code","Alert when LITELLM_LICENSE nears expiry so budgets do not silently stop provisioning","Document which of your key features require the enterprise tier"],"tags":["enterprise","license","budgets","litellm-proxy","keys"],"backgroundTag":"enterprise-license-required","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}