FaceCheck / app /core /exceptions.py
Mukhammadali Bakhodirov
Deploy detection fixes
9b5157d
"""
Domain exception hierarchy.
Each exception maps to an HTTP status code and a machine-readable error_code.
Routers raise these; exception handlers in main.py convert them to HTTP responses.
"""
from typing import Any
class AppError(Exception):
status_code: int = 500
error_code: str = "INTERNAL_ERROR"
def __init__(self, message: str = "An unexpected error occurred", context: dict[str, Any] | None = None):
self.message = message
self.context = context or {}
super().__init__(message)
class ImageDecodeError(AppError):
status_code = 400
error_code = "IMAGE_DECODE_ERROR"
def __init__(self):
super().__init__("Could not decode image. Ensure it is a valid JPEG, PNG, or WebP file.")
class ImageTooLargeError(AppError):
status_code = 413
error_code = "IMAGE_TOO_LARGE"
def __init__(self, max_mb: int = 10, detail: str | None = None):
super().__init__(
detail or f"Image exceeds maximum size of {max_mb}MB.",
context={"max_mb": max_mb},
)
class InvalidMimeTypeError(AppError):
status_code = 415
error_code = "INVALID_MIME_TYPE"
def __init__(self, received: str, allowed: set[str]):
super().__init__(
f"Unsupported file type '{received}'. Allowed: {', '.join(sorted(allowed))}.",
context={"received": received, "allowed": sorted(allowed)},
)
class UnknownChallengeError(AppError):
status_code = 400
error_code = "UNKNOWN_CHALLENGE"
def __init__(self, challenge_type: str, valid: list[str]):
super().__init__(
f"Unknown challenge '{challenge_type}'.",
context={"received": challenge_type, "valid": valid},
)
class ModelNotReadyError(AppError):
status_code = 503
error_code = "MODEL_NOT_READY"
def __init__(self, model_name: str):
super().__init__(
f"Model '{model_name}' is not loaded. Retry in a moment.",
context={"model": model_name},
)
class RateLimitError(AppError):
status_code = 429
error_code = "RATE_LIMIT_EXCEEDED"
def __init__(self):
super().__init__("Too many requests. Please slow down.")