"""OpenAI-style structured errors.""" from __future__ import annotations from fastapi import Request from fastapi.responses import JSONResponse class APIError(Exception): status_code = 400 error_type = "invalid_request_error" code = "INVALID_REQUEST" def __init__(self, message: str, *, status_code: int | None = None, error_type: str | None = None, code: str | None = None, param: str | None = None, extra: dict | None = None): super().__init__(message) self.message = message if status_code is not None: self.status_code = status_code if error_type is not None: self.error_type = error_type if code is not None: self.code = code self.param = param self.extra = extra or {} def to_dict(self) -> dict: err = {"message": self.message, "type": self.error_type, "code": self.code, "param": self.param} err.update(self.extra) return {"error": err} class ModelNotFound(APIError): status_code = 404 error_type = "invalid_request_error" code = "MODEL_NOT_FOUND" class ModelTooLarge(APIError): status_code = 507 error_type = "model_memory_error" code = "MODEL_TOO_LARGE" class ModelIncompatible(APIError): status_code = 422 error_type = "model_compatibility_error" code = "MODEL_INCOMPATIBLE" class ModelLoadError(APIError): status_code = 503 error_type = "model_load_error" code = "MODEL_LOAD_FAILED" class ModelLoadTimeout(ModelLoadError): code = "MODEL_LOAD_TIMEOUT" class WorkerCrashed(APIError): status_code = 503 error_type = "runtime_error" code = "WORKER_CRASHED" class GenerationTimeout(APIError): status_code = 504 error_type = "runtime_error" code = "GENERATION_TIMEOUT" class ContextTooLarge(APIError): status_code = 400 error_type = "invalid_request_error" code = "CONTEXT_TOO_LARGE" class InsufficientDisk(APIError): status_code = 507 error_type = "storage_error" code = "INSUFFICIENT_DISK" class DownloadError(APIError): status_code = 502 error_type = "download_error" code = "DOWNLOAD_FAILED" class AuthError(APIError): status_code = 401 error_type = "authentication_error" code = "INVALID_API_KEY" class Forbidden(APIError): status_code = 403 error_type = "permission_error" code = "FORBIDDEN" class RateLimited(APIError): status_code = 429 error_type = "rate_limit_error" code = "RATE_LIMITED" class Conflict(APIError): status_code = 409 error_type = "invalid_request_error" code = "CONFLICT" class RuntimeUnsupported(APIError): status_code = 422 error_type = "model_compatibility_error" code = "RUNTIME_UNSUPPORTED" async def api_error_handler(_: Request, exc: APIError) -> JSONResponse: return JSONResponse(status_code=exc.status_code, content=exc.to_dict())