From 4b8b7bb557394299d7dbda48db16aaaf94f1a552 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Thu, 5 Mar 2026 15:07:44 -0800 Subject: [PATCH] [Fix] Key Expiry: return 400 for legacy -1 duration, fix Never Expires uncheck - Return HTTP 400 with a clear migration message when duration="-1" is passed to the upperbound validation path, instead of crashing with an unhandled ValueError (500). - Fix KeyLifecycleSettings: add else branch to handleNeverExpiresChange so unchecking "Never Expires" resets the form's duration field to undefined, preventing it from being submitted as null (never-expires). Co-Authored-By: Claude Sonnet 4.6 --- .../proxy/management_endpoints/key_management_endpoints.py | 7 +++++++ .../components/common_components/KeyLifecycleSettings.tsx | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/litellm/proxy/management_endpoints/key_management_endpoints.py b/litellm/proxy/management_endpoints/key_management_endpoints.py index 82db6e140e8..45542cba7a3 100644 --- a/litellm/proxy/management_endpoints/key_management_endpoints.py +++ b/litellm/proxy/management_endpoints/key_management_endpoints.py @@ -534,6 +534,13 @@ async def _common_key_generation_helper( # noqa: PLR0915 upperbound_duration = duration_in_seconds( duration=upperbound_value ) + if value == "-1": + raise HTTPException( + status_code=400, + detail={ + "error": "'-1' is no longer a valid duration value. Pass duration: null to set a key to never expire." + }, + ) user_duration = duration_in_seconds(duration=value) if user_duration > upperbound_duration: raise HTTPException( diff --git a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx index e7a0bff41a8..3b0f27a0cbd 100644 --- a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx +++ b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.tsx @@ -69,6 +69,13 @@ const KeyLifecycleSettings: React.FC = ({ } else if (form && typeof form.setFieldsValue === "function") { form.setFieldsValue({ duration: null }); } + } else { + // Clear the null so duration is omitted from the request (not sent as never-expires) + if (form && typeof form.setFieldValue === "function") { + form.setFieldValue("duration", undefined); + } else if (form && typeof form.setFieldsValue === "function") { + form.setFieldsValue({ duration: undefined }); + } } };