From 0bd002c8527f6c2f7c716ae742c9894c3908a3c9 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 11 Mar 2026 09:23:44 -0700 Subject: [PATCH] fix: forward OAuth error params in callback, fix BYOK guard exception handling in db.py --- litellm/proxy/_experimental/mcp_server/db.py | 16 ++++++++-------- .../src/app/mcp/oauth/callback/page.tsx | 4 ++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/litellm/proxy/_experimental/mcp_server/db.py b/litellm/proxy/_experimental/mcp_server/db.py index 72875b5cf8d..d830d19618c 100644 --- a/litellm/proxy/_experimental/mcp_server/db.py +++ b/litellm/proxy/_experimental/mcp_server/db.py @@ -506,17 +506,17 @@ async def store_user_oauth_credential( where={"user_id_server_id": {"user_id": user_id, "server_id": server_id}} ) if existing is not None: + _byok_error = ValueError( + f"A non-OAuth2 credential already exists for user {user_id} " + f"and server {server_id}. Refusing to overwrite." + ) try: raw = json.loads(base64.urlsafe_b64decode(existing.credential_b64).decode()) - if raw.get("type") != "oauth2": - raise ValueError( - f"A non-OAuth2 credential already exists for user {user_id} " - f"and server {server_id}. Refusing to overwrite." - ) - except (ValueError, KeyError): - raise except Exception: - pass # Malformed existing record — allow overwrite + # Credential is not base64+JSON — it's a plain-text BYOK key. + raise _byok_error + if raw.get("type") != "oauth2": + raise _byok_error encoded = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode() await prisma_client.db.litellm_mcpusercredentials.upsert( diff --git a/ui/litellm-dashboard/src/app/mcp/oauth/callback/page.tsx b/ui/litellm-dashboard/src/app/mcp/oauth/callback/page.tsx index 390a5d6925c..0c4cad8cb0b 100644 --- a/ui/litellm-dashboard/src/app/mcp/oauth/callback/page.tsx +++ b/ui/litellm-dashboard/src/app/mcp/oauth/callback/page.tsx @@ -36,6 +36,10 @@ const McpOAuthCallbackContent = () => { type: "litellm-mcp-oauth", code: searchParams.get("code"), state: searchParams.get("state"), + // Forward OAuth provider error params so the hook can surface the real + // reason (e.g. "access_denied") instead of a generic "code missing" error. + error: searchParams.get("error"), + error_description: searchParams.get("error_description"), }; }, [searchParams]);