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