|
46 | 46 | WebSocketDisconnect,
|
47 | 47 | )
|
48 | 48 | from fastapi.background import BackgroundTasks
|
| 49 | +from fastapi.exception_handlers import request_validation_exception_handler as fastapi_default_validation_handler |
| 50 | +from fastapi.exceptions import RequestValidationError |
49 | 51 | from fastapi.middleware.cors import CORSMiddleware
|
50 | 52 | from fastapi.responses import JSONResponse, RedirectResponse, StreamingResponse
|
51 | 53 | from fastapi.staticfiles import StaticFiles
|
@@ -290,6 +292,41 @@ async def validation_exception_handler(_request: Request, exc: ValidationError):
|
290 | 292 | return JSONResponse(status_code=422, content=ErrorFormatter.format_validation_error(exc))
|
291 | 293 |
|
292 | 294 |
|
| 295 | +@app.exception_handler(RequestValidationError) |
| 296 | +async def request_validation_exception_handler(_request: Request, exc: RequestValidationError): |
| 297 | + """Handle FastAPI request validation errors (automatic request parsing). |
| 298 | +
|
| 299 | + This handles ValidationErrors that occur during FastAPI's automatic request |
| 300 | + parsing before the request reaches your endpoint. |
| 301 | +
|
| 302 | + Args: |
| 303 | + _request: The FastAPI request object that triggered validation error. |
| 304 | + exc: The RequestValidationError exception containing failure details. |
| 305 | +
|
| 306 | + Returns: |
| 307 | + JSONResponse: A 422 Unprocessable Entity response with error details. |
| 308 | + """ |
| 309 | + if _request.url.path.startswith("/tools"): |
| 310 | + error_details = [] |
| 311 | + |
| 312 | + for error in exc.errors(): |
| 313 | + loc = error.get("loc", []) |
| 314 | + msg = error.get("msg", "Unknown error") |
| 315 | + ctx = error.get("ctx", {"error": {}}) |
| 316 | + type_ = error.get("type", "value_error") |
| 317 | + # Ensure ctx is JSON serializable |
| 318 | + if isinstance(ctx, dict): |
| 319 | + ctx_serializable = {k: (str(v) if isinstance(v, Exception) else v) for k, v in ctx.items()} |
| 320 | + else: |
| 321 | + ctx_serializable = str(ctx) |
| 322 | + error_detail = {"type": type_, "loc": loc, "msg": msg, "ctx": ctx_serializable} |
| 323 | + error_details.append(error_detail) |
| 324 | + |
| 325 | + response_content = {"detail": error_details} |
| 326 | + return JSONResponse(status_code=422, content=response_content) |
| 327 | + return await fastapi_default_validation_handler(_request, exc) |
| 328 | + |
| 329 | + |
293 | 330 | @app.exception_handler(IntegrityError)
|
294 | 331 | async def database_exception_handler(_request: Request, exc: IntegrityError):
|
295 | 332 | """Handle SQLAlchemy database integrity constraint violations globally.
|
|
0 commit comments