diff --git a/ui/litellm-dashboard/src/app/(dashboard)/layout.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/layout.test.tsx
new file mode 100644
index 00000000000..af68d9f87e9
--- /dev/null
+++ b/ui/litellm-dashboard/src/app/(dashboard)/layout.test.tsx
@@ -0,0 +1,78 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { render, screen, waitFor } from "@testing-library/react";
+import { AuthProvider } from "@/contexts/AuthContext";
+import Layout from "./layout";
+
+vi.mock("next/navigation", () => ({
+ useRouter: vi.fn(() => ({ push: vi.fn(), replace: vi.fn() })),
+ useSearchParams: vi.fn(() => new URLSearchParams()),
+ usePathname: vi.fn(() => "/ui/guardrails"),
+}));
+
+vi.mock("@/components/navbar", () => ({
+ default: () =>
,
+}));
+
+vi.mock("@/app/(dashboard)/components/SidebarProvider", () => ({
+ default: () => ,
+}));
+
+vi.mock("@/components/DebugWarningBanner", () => ({
+ DebugWarningBanner: () => null,
+}));
+
+vi.mock("@/contexts/ThemeContext", () => ({
+ ThemeProvider: ({ children }: { children: React.ReactNode }) => <>{children}>,
+}));
+
+vi.mock("@/components/common_components/LoadingScreen", () => ({
+ default: () => ,
+}));
+
+type Deferred = { promise: Promise; resolve: () => void };
+
+const createDeferred = (): Deferred => {
+ let resolve!: () => void;
+ const promise = new Promise((r) => {
+ resolve = r;
+ });
+ return { promise, resolve };
+};
+
+let pendingUiConfig: Deferred;
+
+vi.mock("@/components/networking", async (importOriginal) => {
+ const actual = await importOriginal();
+ return {
+ ...actual,
+ getUiConfig: vi.fn(() => pendingUiConfig.promise),
+ setGlobalLitellmHeaderName: vi.fn(),
+ };
+});
+
+describe("(dashboard) Layout", () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ pendingUiConfig = createDeferred();
+ });
+
+ it("does not mount route content until getUiConfig has resolved", async () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ await waitFor(() => expect(screen.getByTestId("loading-screen")).toBeTruthy());
+ expect(screen.queryByTestId("page-content")).toBeNull();
+ expect(screen.queryByTestId("navbar")).toBeNull();
+
+ pendingUiConfig.resolve();
+
+ await waitFor(() => expect(screen.getByTestId("page-content")).toBeTruthy());
+ expect(screen.getByTestId("navbar")).toBeTruthy();
+ expect(screen.queryByTestId("loading-screen")).toBeNull();
+ });
+});
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/layout.tsx b/ui/litellm-dashboard/src/app/(dashboard)/layout.tsx
index df5b2ab4511..b32bed44a87 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/layout.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/layout.tsx
@@ -45,9 +45,13 @@ function DashboardShell({ children }: { children: React.ReactNode }) {
function LayoutContent({ children }: { children: React.ReactNode }) {
const searchParams = useSearchParams();
- const { accessToken } = useAuth();
+ const { accessToken, authLoading } = useAuth();
const isInvitationFlow = Boolean(searchParams.get("invitation_id"));
+ if (authLoading) {
+ return ;
+ }
+
return (
{isInvitationFlow ? children : {children}}