File size: 1,632 Bytes
f2fecbd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | """Map exceptions to consistent JSON error responses."""
from __future__ import annotations
import logging
from flask import Flask, current_app, jsonify
from werkzeug.exceptions import HTTPException, RequestEntityTooLarge
from ..exceptions import AppError
logger = logging.getLogger(__name__)
def _error_body(message: str, status: int, detail: str = "", project_id: str = ""):
body = {"message": message, "isError": True}
# Internal details go to clients only for client errors, or when DEBUG is on.
if detail and (status < 500 or current_app.config["SETTINGS"].debug):
body["error"] = detail
if project_id:
body["project_id"] = project_id # lets support correlate with the server logs
return jsonify(body), status
def register_error_handlers(app: Flask) -> None:
@app.errorhandler(AppError)
def handle_app_error(e: AppError):
if e.status_code >= 500:
logger.error("Project %s failed: %s", e.project_id or "-", e.detail or e)
return _error_body(e.public_message, e.status_code, e.detail, e.project_id)
@app.errorhandler(RequestEntityTooLarge)
def handle_too_large(e):
limit = current_app.config["SETTINGS"].max_upload_mb
return _error_body(f"❌ File too large (max {limit} MB)", 413)
@app.errorhandler(Exception)
def handle_unexpected(e: Exception):
if isinstance(e, HTTPException): # 404/405 etc. keep their normal status
return _error_body(e.description or e.name, e.code or 500)
logger.exception("Unhandled error")
return _error_body("❌ Internal server error", 500, str(e))
|