From 2ae75846869d94c05ccb5a25fe1073a69b1d4089 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Fri, 8 Aug 2025 09:38:34 -0400 Subject: [PATCH] feat: forward upstream OpenAI errors --- backend/open_webui/routers/openai.py | 116 ++++++++++++++------------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index e26ef24d0b..dad545c3bd 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -2,17 +2,15 @@ import asyncio import hashlib import json import logging -from pathlib import Path -from typing import Literal, Optional, overload +from typing import Optional import aiohttp from aiocache import cached import requests from urllib.parse import quote -from fastapi import Depends, FastAPI, HTTPException, Request, APIRouter -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import FileResponse, StreamingResponse +from fastapi import Depends, HTTPException, Request, APIRouter +from fastapi.responses import FileResponse, StreamingResponse, JSONResponse, PlainTextResponse from pydantic import BaseModel from starlette.background import BackgroundTask @@ -31,7 +29,7 @@ from open_webui.env import ( from open_webui.models.users import UserModel from open_webui.constants import ERROR_MESSAGES -from open_webui.env import ENV, SRC_LOG_LEVELS +from open_webui.env import SRC_LOG_LEVELS from open_webui.utils.payload import ( @@ -595,15 +593,17 @@ async def verify_connection( headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as r: - if r.status != 200: - # Extract response error details if available - error_detail = f"HTTP Error: {r.status}" - res = await r.json() - if "error" in res: - error_detail = f"External Error: {res['error']}" - raise Exception(error_detail) + try: + response_data = await r.json() + except Exception: + response_data = await r.text() + + if r.status != 200: + if isinstance(response_data, (dict, list)): + return JSONResponse(status_code=r.status, content=response_data) + else: + return PlainTextResponse(status_code=r.status, content=response_data) - response_data = await r.json() return response_data else: headers["Authorization"] = f"Bearer {key}" @@ -613,15 +613,17 @@ async def verify_connection( headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as r: - if r.status != 200: - # Extract response error details if available - error_detail = f"HTTP Error: {r.status}" - res = await r.json() - if "error" in res: - error_detail = f"External Error: {res['error']}" - raise Exception(error_detail) + try: + response_data = await r.json() + except Exception: + response_data = await r.text() + + if r.status != 200: + if isinstance(response_data, (dict, list)): + return JSONResponse(status_code=r.status, content=response_data) + else: + return PlainTextResponse(status_code=r.status, content=response_data) - response_data = await r.json() return response_data except aiohttp.ClientError as e: @@ -632,8 +634,9 @@ async def verify_connection( ) except Exception as e: log.exception(f"Unexpected error: {e}") - error_detail = f"Unexpected error: {str(e)}" - raise HTTPException(status_code=500, detail=error_detail) + raise HTTPException( + status_code=500, detail="Open WebUI: Server Connection Error" + ) def get_azure_allowed_params(api_version: str) -> set[str]: @@ -883,21 +886,19 @@ async def generate_chat_completion( log.error(e) response = await r.text() - r.raise_for_status() + if r.status >= 400: + if isinstance(response, (dict, list)): + return JSONResponse(status_code=r.status, content=response) + else: + return PlainTextResponse(status_code=r.status, content=response) + return response except Exception as e: log.exception(e) - detail = None - if isinstance(response, dict): - if "error" in response: - detail = f"{response['error']['message'] if 'message' in response['error'] else response['error']}" - elif isinstance(response, str): - detail = response - raise HTTPException( status_code=r.status if r else 500, - detail=detail if detail else "Open WebUI: Server Connection Error", + detail="Open WebUI: Server Connection Error", ) finally: if not streaming: @@ -951,7 +952,7 @@ async def embeddings(request: Request, form_data: dict, user): ), }, ) - r.raise_for_status() + if "text/event-stream" in r.headers.get("Content-Type", ""): streaming = True return StreamingResponse( @@ -963,21 +964,23 @@ async def embeddings(request: Request, form_data: dict, user): ), ) else: - response_data = await r.json() + try: + response_data = await r.json() + except Exception: + response_data = await r.text() + + if r.status >= 400: + if isinstance(response_data, (dict, list)): + return JSONResponse(status_code=r.status, content=response_data) + else: + return PlainTextResponse(status_code=r.status, content=response_data) + return response_data except Exception as e: log.exception(e) - detail = None - if r is not None: - try: - res = await r.json() - if "error" in res: - detail = f"External: {res['error']['message'] if 'message' in res['error'] else res['error']}" - except Exception: - detail = f"External: {e}" raise HTTPException( status_code=r.status if r else 500, - detail=detail if detail else "Open WebUI: Server Connection Error", + detail="Open WebUI: Server Connection Error", ) finally: if not streaming: @@ -1043,7 +1046,6 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)): headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL, ) - r.raise_for_status() # Check if response is SSE if "text/event-stream" in r.headers.get("Content-Type", ""): @@ -1057,24 +1059,24 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)): ), ) else: - response_data = await r.json() + try: + response_data = await r.json() + except Exception: + response_data = await r.text() + + if r.status >= 400: + if isinstance(response_data, (dict, list)): + return JSONResponse(status_code=r.status, content=response_data) + else: + return PlainTextResponse(status_code=r.status, content=response_data) + return response_data except Exception as e: log.exception(e) - - detail = None - if r is not None: - try: - res = await r.json() - log.error(res) - if "error" in res: - detail = f"External: {res['error']['message'] if 'message' in res['error'] else res['error']}" - except Exception: - detail = f"External: {e}" raise HTTPException( status_code=r.status if r else 500, - detail=detail if detail else "Open WebUI: Server Connection Error", + detail="Open WebUI: Server Connection Error", ) finally: if not streaming: