{"record":{"id":"5a7b5f9a87196196","repo":"BerriAI/litellm","slug":"code-challenge-is-required","errorCode":null,"errorMessage":"code_challenge is required","messagePattern":"code_challenge is required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"litellm/proxy/_experimental/mcp_server/byok_oauth_endpoints.py","lineNumber":661,"sourceCode":"    \"\"\"\n    Show the BYOK API-key entry form.\n\n    The MCP client navigates the user here; the user types their API key and\n    clicks \"Connect & Authorize\", which POSTs back to this same path.\n\n    This GET is intentionally unauthenticated: it only renders HTML with no\n    state change. The POST handler enforces ``user_api_key_auth`` and pins\n    the stored credential to the authenticated session.\n    \"\"\"\n    if response_type != \"code\":\n        raise HTTPException(status_code=400, detail=\"response_type must be 'code'\")\n    if not redirect_uri:\n        raise HTTPException(status_code=400, detail=\"redirect_uri is required\")\n    # Validate here too so the user sees the rejection before typing their\n    # API key into the HTML form (the POST handler also validates).\n    validate_loopback_redirect_uri(redirect_uri)\n    if not code_challenge:\n        raise HTTPException(status_code=400, detail=\"code_challenge is required\")\n\n    # Resolve server metadata (name, description items, help URL).\n    server_name = \"MCP Server\"\n    access_items: list = []\n    help_url = \"\"\n    if server_id:\n        try:\n            from litellm.proxy._experimental.mcp_server.mcp_server_manager import (\n                global_mcp_server_manager,\n            )\n\n            registry: Final = global_mcp_server_manager.get_registry()\n            if server_id in registry:\n                srv: Final = registry[server_id]\n                server_name = srv.server_name or srv.name\n                access_items = list(srv.byok_description or [])\n                help_url = srv.byok_api_key_help_url or \"\"\n        except Exception:","sourceCodeStart":643,"sourceCodeEnd":679,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/_experimental/mcp_server/byok_oauth_endpoints.py#L643-L679","documentation":"HTTP 400 on the BYOK authorize flow: PKCE is mandatory, and the request carried no code_challenge. Without it the issued authorization code could be intercepted and redeemed, so the flow refuses to start.","triggerScenarios":"Thrown at litellm/proxy/_experimental/mcp_server/byok_oauth_endpoints.py:661 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Include a PKCE code_challenge (S256) in the authorization request."],"exampleFix":"code_challenge=base64url(sha256(verifier))&code_challenge_method=S256","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}