diff --git a/backend/open_webui/routers/audio.py b/backend/open_webui/routers/audio.py index 926380bf52..ee136e833e 100644 --- a/backend/open_webui/routers/audio.py +++ b/backend/open_webui/routers/audio.py @@ -58,6 +58,7 @@ from open_webui.events import EVENTS, publish_event from open_webui.models.config import Config from open_webui.utils.access_control import has_permission from open_webui.utils.auth import get_admin_user, get_verified_user +from open_webui.utils.errors import error_detail from open_webui.utils.headers import include_user_info_headers from open_webui.utils.misc import strict_match_mime_type from open_webui.utils.session_pool import get_session @@ -1055,7 +1056,7 @@ async def transcribe(request: Request, file_path: str, metadata: Optional[dict] log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error processing audio file'), ) results = [] diff --git a/backend/open_webui/routers/functions.py b/backend/open_webui/routers/functions.py index ea6b66e0d3..cd9a421523 100644 --- a/backend/open_webui/routers/functions.py +++ b/backend/open_webui/routers/functions.py @@ -22,6 +22,7 @@ from open_webui.models.functions import ( FunctionWithValvesModel, ) from open_webui.utils.auth import get_admin_user, get_verified_user +from open_webui.utils.errors import error_detail from open_webui.utils.plugin import ( get_functions_cache, get_function_module_from_cache, @@ -133,7 +134,7 @@ async def load_function_from_url(request: Request, form_data: LoadUrlForm, user= 'content': data, } except Exception as e: - raise HTTPException(status_code=500, detail=ERROR_MESSAGES.DEFAULT(e)) + raise HTTPException(status_code=500, detail=error_detail(e, 'Error fetching function')) ############################ @@ -173,7 +174,7 @@ async def sync_functions( log.exception(f'Failed to load a function: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error loading function'), ) @@ -236,7 +237,7 @@ async def create_new_function( log.exception(f'Failed to create a new function: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error creating function'), ) else: raise HTTPException( @@ -384,7 +385,7 @@ async def update_function_by_id( except Exception as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error updating function'), ) @@ -432,7 +433,7 @@ async def get_function_valves_by_id( except Exception as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error getting function valves'), ) else: raise HTTPException( @@ -508,7 +509,7 @@ async def update_function_valves_by_id( log.exception(f'Error updating function values by id {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error updating function valves'), ) else: raise HTTPException( @@ -540,7 +541,7 @@ async def get_function_user_valves_by_id( except Exception as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error getting function user valves'), ) else: raise HTTPException( @@ -607,7 +608,7 @@ async def update_function_user_valves_by_id( log.exception(f'Error updating function user valves by id {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error updating function user valves'), ) else: raise HTTPException( diff --git a/backend/open_webui/routers/groups.py b/backend/open_webui/routers/groups.py index b4afa897bf..7bd70b3fc7 100755 --- a/backend/open_webui/routers/groups.py +++ b/backend/open_webui/routers/groups.py @@ -22,6 +22,7 @@ from open_webui.models.models import Models from open_webui.models.tools import Tools from open_webui.models.users import UserInfoResponse, Users from open_webui.utils.auth import get_admin_user, get_verified_user +from open_webui.utils.errors import error_detail from sqlalchemy.ext.asyncio import AsyncSession log = logging.getLogger(__name__) @@ -87,7 +88,7 @@ async def create_new_group( log.exception(f'Error creating a new group: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error creating group'), ) @@ -166,7 +167,7 @@ async def get_users_in_group(id: str, user=Depends(get_admin_user), db: AsyncSes log.exception(f'Error adding users to group {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error getting group members'), ) @@ -206,7 +207,7 @@ async def update_group_by_id( log.exception(f'Error updating group {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error updating group'), ) @@ -249,7 +250,7 @@ async def add_user_to_group( log.exception(f'Error adding users to group {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error adding users to group'), ) @@ -284,7 +285,7 @@ async def remove_users_from_group( log.exception(f'Error removing users from group {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error removing users from group'), ) @@ -316,7 +317,7 @@ async def delete_group_by_id( log.exception(f'Error deleting group {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error deleting group'), ) diff --git a/backend/open_webui/routers/images.py b/backend/open_webui/routers/images.py index 5bfb89357b..51d2cb4731 100644 --- a/backend/open_webui/routers/images.py +++ b/backend/open_webui/routers/images.py @@ -31,6 +31,7 @@ from open_webui.retrieval.web.utils import get_ssrf_safe_session, validate_url from open_webui.routers.files import get_file_content_by_id, upload_file_handler from open_webui.utils.access_control import has_permission from open_webui.utils.auth import get_admin_user, get_verified_user +from open_webui.utils.errors import error_detail from open_webui.utils.headers import include_user_info_headers from open_webui.utils.images.comfyui import ( ComfyUICreateImageForm, @@ -166,7 +167,11 @@ async def get_image_model(request): options = await r.json() return options['sd_model_checkpoint'] except Exception as e: - raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) + log.exception(f'Failed to get default model from automatic1111: {e}') + raise HTTPException( + status_code=400, + detail=error_detail(e, 'Failed to connect to the image generation engine'), + ) class ImagesConfig(BaseModel): @@ -383,7 +388,8 @@ async def get_models(request: Request, user=Depends(get_verified_user)): ) ) except Exception as e: - raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) + log.exception(f'Failed to list image generation models: {e}') + raise HTTPException(status_code=400, detail=error_detail(e, 'Failed to retrieve image generation models')) class CreateImageForm(BaseModel): @@ -900,7 +906,7 @@ async def image_edits( # Load all images in parallel for better performance form_data.image = list(await asyncio.gather(*[load_url_image(img) for img in form_data.image])) except Exception as e: - raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) + raise HTTPException(status_code=400, detail=error_detail(e, 'Error loading image')) def get_image_file_item(base64_string, param_name='image'): data = base64_string diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index 080a344a36..9a18bbc7a4 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -118,6 +118,7 @@ from open_webui.storage.provider import Storage from open_webui.utils.access_control import has_permission from open_webui.utils.access_control.files import has_access_to_file from open_webui.utils.auth import get_admin_user, get_verified_user +from open_webui.utils.errors import error_detail from open_webui.utils.misc import ( calculate_sha256_string, sanitize_text_for_db, @@ -182,7 +183,7 @@ def get_rf( except Exception as e: log.error(f'ColBERT: {e}') - raise Exception(ERROR_MESSAGES.DEFAULT(e)) + raise Exception(error_detail(e, 'Error loading reranking model')) else: if engine == 'external': try: @@ -196,7 +197,7 @@ def get_rf( ) except Exception as e: log.error(f'ExternalReranking: {e}') - raise Exception(ERROR_MESSAGES.DEFAULT(e)) + raise Exception(error_detail(e, 'Error loading reranking model')) else: import sentence_transformers import torch @@ -605,7 +606,7 @@ async def update_embedding_config(request: Request, form_data: EmbeddingModelUpd log.exception(f'Problem updating embedding model: {e}') raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error updating embedding configuration'), ) @@ -1207,7 +1208,7 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend log.exception(f'Problem updating reranking model: {e}') raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error updating reranking configuration'), ) # Chunking settings @@ -2149,7 +2150,7 @@ async def process_web( log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error querying knowledge base'), ) @@ -2654,7 +2655,10 @@ async def process_web_search(request: Request, form_data: SearchForm, user=Depen } except Exception as e: log.exception('Web search content loading failed') - raise HTTPException(status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT(e)) + raise HTTPException( + status.HTTP_400_BAD_REQUEST, + detail=error_detail(e, ERROR_MESSAGES.WEB_SEARCH_ERROR()), + ) async def _validate_collection_access(collection_names: list[str], user, access_type: str = 'read') -> None: @@ -2732,7 +2736,7 @@ async def query_doc_handler( log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error querying knowledge base'), ) @@ -2798,7 +2802,7 @@ async def query_collection_handler( log.exception(e) raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(e), + detail=error_detail(e, 'Error querying knowledge base'), ) diff --git a/backend/open_webui/routers/skills.py b/backend/open_webui/routers/skills.py index e92143aee1..77f3351c2b 100644 --- a/backend/open_webui/routers/skills.py +++ b/backend/open_webui/routers/skills.py @@ -20,6 +20,7 @@ from open_webui.models.skills import ( ) from open_webui.utils.access_control import filter_allowed_access_grants, has_permission from open_webui.utils.auth import get_admin_user, get_verified_user +from open_webui.utils.errors import error_detail from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession @@ -213,7 +214,7 @@ async def create_new_skill( log.exception(f'Failed to create skill: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(str(e)), + detail=error_detail(e, 'Error creating skill'), ) @@ -337,7 +338,7 @@ async def update_skill_by_id( except Exception as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(str(e)), + detail=error_detail(e, 'Error updating skill'), ) diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index 415e71fd02..63440e1299 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -31,6 +31,7 @@ from open_webui.utils.access_control import ( has_permission, ) from open_webui.utils.auth import get_admin_user, get_verified_user +from open_webui.utils.errors import error_detail from open_webui.utils.plugin import ( get_tools_cache, get_tool_module_from_cache, @@ -295,7 +296,7 @@ async def load_tool_from_url(request: Request, form_data: LoadUrlForm, user=Depe 'content': data, } except Exception as e: - raise HTTPException(status_code=500, detail=ERROR_MESSAGES.DEFAULT(e)) + raise HTTPException(status_code=500, detail=error_detail(e, 'Error fetching tool')) ############################ @@ -404,7 +405,7 @@ async def create_new_tools( log.exception(f'Failed to load the tool by id {form_data.id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(str(e)), + detail=error_detail(e, 'Error creating tool'), ) else: raise HTTPException( @@ -554,7 +555,7 @@ async def update_tools_by_id( except Exception as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(str(e)), + detail=error_detail(e, 'Error updating tool'), ) @@ -707,7 +708,7 @@ async def get_tools_valves_by_id( except Exception as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(str(e)), + detail=error_detail(e, 'Error getting tool valves'), ) @@ -818,7 +819,7 @@ async def update_tools_valves_by_id( log.exception(f'Failed to update tool valves by id {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(str(e)), + detail=error_detail(e, 'Error updating tool valves'), ) @@ -860,7 +861,7 @@ async def get_tools_user_valves_by_id( except Exception as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(str(e)), + detail=error_detail(e, 'Error getting tool user valves'), ) @@ -958,7 +959,7 @@ async def update_tools_user_valves_by_id( log.exception(f'Failed to update user valves by id {id}: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT(str(e)), + detail=error_detail(e, 'Error updating tool user valves'), ) else: raise HTTPException( diff --git a/backend/open_webui/utils/errors.py b/backend/open_webui/utils/errors.py new file mode 100644 index 0000000000..89dcc2aa08 --- /dev/null +++ b/backend/open_webui/utils/errors.py @@ -0,0 +1,25 @@ +import errno + +from fastapi import HTTPException + +from open_webui.constants import ERROR_MESSAGES + + +OS_ERROR_MESSAGES = { + errno.ENAMETOOLONG: 'File name is too long.', + errno.ENOSPC: 'The server is out of storage space.', + errno.EDQUOT: 'Server storage quota exceeded.', + errno.EACCES: 'Server storage is not writable.', + errno.EPERM: 'Server storage is not writable.', + errno.EROFS: 'Server storage is not writable.', +} + + +def error_detail(exc: Exception, fallback: str = '') -> str: + if isinstance(exc, HTTPException) and exc.detail: + return exc.detail if isinstance(exc.detail, str) else ERROR_MESSAGES.DEFAULT(fallback) + + if isinstance(exc, OSError) and exc.errno in OS_ERROR_MESSAGES: + return ERROR_MESSAGES.DEFAULT(OS_ERROR_MESSAGES[exc.errno]) + + return ERROR_MESSAGES.DEFAULT(fallback)