From 1c01bbccb7e6a38a48866570d50dcdd23f6528ab Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Mon, 27 Jul 2026 01:02:10 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20422=20errors=20on=20all=20plugin=20route?= =?UTF-8?q?s=20=E2=80=94=20wrapper(*args,=20**kwargs)=20was=20interpreted?= =?UTF-8?q?=20as=20query=20params=20by=20FastAPI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wrap_plugin_route wrapper had *args, **kwargs as parameters. FastAPI interpreted these as required query parameters 'args' and 'kwargs', causing 422 Unprocessable Entity on EVERY plugin route (mail, calendar, dms, reports, etc.). Fix: Use functools.wraps(handler) to copy the original signature, then remove __annotations__ (to avoid ForwardRef('UploadFile') issues), and manually set __signature__ from the original handler. --- app/core/plugin_error_handler.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/app/core/plugin_error_handler.py b/app/core/plugin_error_handler.py index 669775d..64546bc 100644 --- a/app/core/plugin_error_handler.py +++ b/app/core/plugin_error_handler.py @@ -1,6 +1,7 @@ """Plugin error isolation wrapper.""" import logging import functools +import inspect from fastapi import UploadFile as _UploadFile # noqa: F401 — needed for ForwardRef resolution from fastapi.responses import JSONResponse @@ -10,10 +11,11 @@ logger = logging.getLogger(__name__) def wrap_plugin_route(handler): """Decorator that isolates plugin route errors and returns structured JSON. - Does NOT use functools.wraps to avoid copying __annotations__ and - __wrapped__ — FastAPI would otherwise try to resolve - ``ForwardRef('UploadFile')`` from the original handler's signature. + Copies the original handler's signature so FastAPI sees the correct + parameters (path params, query params, body, etc.) instead of *args/**kwargs. + Avoids copying __annotations__ to prevent ForwardRef('UploadFile') issues. """ + @functools.wraps(handler) async def wrapper(*args, **kwargs): try: return await handler(*args, **kwargs) @@ -23,8 +25,16 @@ def wrap_plugin_route(handler): status_code=500, content={'detail': f'Plugin error: {exc}', 'code': 'plugin_error'} ) - # Preserve identity for debugging but NOT __wrapped__ or __annotations__ - wrapper.__name__ = getattr(handler, '__name__', 'wrapper') - wrapper.__module__ = getattr(handler, '__module__', __name__) - wrapper.__qualname__ = getattr(handler, '__qualname__', 'wrapper') + # Remove annotations that cause ForwardRef resolution issues + wrapper.__annotations__ = {} + # Remove __wrapped__ so FastAPI doesn't try to resolve the original signature + # (which may have ForwardRef('UploadFile') that can't be resolved) + if hasattr(wrapper, '__wrapped__'): + delattr(wrapper, '__wrapped__') + # Copy the signature from the original handler so FastAPI sees correct params + try: + orig_sig = inspect.signature(handler) + wrapper.__signature__ = orig_sig + except (ValueError, TypeError): + pass return wrapper