diff --git a/ui/litellm-dashboard/src/components/LicenseExpiryBanner.test.tsx b/ui/litellm-dashboard/src/components/LicenseExpiryBanner.test.tsx
index 781654ac2f8..e9def76f9cd 100644
--- a/ui/litellm-dashboard/src/components/LicenseExpiryBanner.test.tsx
+++ b/ui/litellm-dashboard/src/components/LicenseExpiryBanner.test.tsx
@@ -147,8 +147,9 @@ describe("LicenseExpiryBanner", () => {
});
it("should handle expiration_date with a full ISO timestamp (not just date-only)", async () => {
- // Backend might return "2026-03-22T15:00:00Z" instead of "2026-03-22"
- // The component should strip the time part and still render correctly.
+ // Backend might return "2026-03-22T15:00:00Z" instead of "2026-03-22".
+ // The component strips the time part ("2026-03-22") and appends "T23:59:59Z",
+ // so the result is the same 8-day countdown as the date-only input.
mockGetLicenseInfo.mockResolvedValue(makeLicense("2026-03-22T15:00:00Z"));
render();
@@ -173,14 +174,17 @@ describe("LicenseExpiryBanner", () => {
});
});
- it("should show a warning when getLicenseInfo API call fails", async () => {
+ it("should not show error banner on first fetch failure for non-enterprise users", async () => {
mockGetLicenseInfo.mockRejectedValue(new Error("Network error"));
- render();
-
- expect(
- await screen.findByText("Unable to verify enterprise license")
- ).toBeInTheDocument();
+ const { container } = render();
+ await waitFor(() => {
+ expect(mockGetLicenseInfo).toHaveBeenCalled();
+ });
+ // Non-enterprise users (no prior license info) should not see the error banner
+ await waitFor(() => {
+ expect(screen.queryByRole("alert")).toBeNull();
+ });
});
it("should render nothing when expiration_date is unparseable", async () => {
diff --git a/ui/litellm-dashboard/src/components/LicenseExpiryBanner.tsx b/ui/litellm-dashboard/src/components/LicenseExpiryBanner.tsx
index 615be1ff979..d802ed56ad5 100644
--- a/ui/litellm-dashboard/src/components/LicenseExpiryBanner.tsx
+++ b/ui/litellm-dashboard/src/components/LicenseExpiryBanner.tsx
@@ -18,8 +18,11 @@ export const LicenseExpiryBanner: React.FC = () => {
if (!accessToken) return;
let cancelled = false;
+ let inFlight = false;
const fetchLicense = () => {
+ if (inFlight) return; // skip if a previous request is still pending
+ inFlight = true;
getLicenseInfo(accessToken)
.then((info) => {
if (!cancelled) {
@@ -29,6 +32,9 @@ export const LicenseExpiryBanner: React.FC = () => {
})
.catch(() => {
if (!cancelled) setFetchError(true);
+ })
+ .finally(() => {
+ inFlight = false;
});
};
@@ -41,7 +47,10 @@ export const LicenseExpiryBanner: React.FC = () => {
};
}, [accessToken]);
- if (fetchError) {
+ // Only show a fetch-error banner if we previously confirmed this is an
+ // enterprise license holder. This prevents non-enterprise users from seeing
+ // a misleading "Unable to verify enterprise license" warning on network errors.
+ if (fetchError && licenseInfo?.has_license) {
return (