Files
ComfyUI-OpenClaw/api/errors.py
T

97 lines
2.4 KiB
Python

"""
R61: Unified API Error Contract.
Provides a shared local exception schema and response serializer.
"""
import json
from enum import Enum
from typing import Any, Dict, Optional
# CI guard: Keep importable even without aiohttp installed
try:
from aiohttp import web
except ImportError:
web = None
class ErrorCode(str, Enum):
"""Standard machine-readable error codes."""
# Dependency / Runtime
DEPENDENCY_UNAVAILABLE = "dependency_unavailable"
INTERNAL_ERROR = "internal_error"
# Validation
VALIDATION_ERROR = "validation_error"
INVALID_REQUEST = "invalid_request"
INVALID_JSON = "invalid_json"
# Queue
QUEUE_SUBMIT_FAILED = "queue_submit_failed"
QUEUE_FULL = "queue_full"
# Auth
AUTH_FAILED = "auth_failed"
FORBIDDEN = "forbidden"
# Request / IO
RATE_LIMIT_EXCEEDED = "rate_limit_exceeded"
UNSUPPORTED_MEDIA_TYPE = "unsupported_media_type"
PAYLOAD_TOO_LARGE = "payload_too_large"
READ_ERROR = "read_error"
class APIError(Exception):
"""
Base class for API-contract exceptions.
Carries status code, machine error code, and human message.
"""
def __init__(
self,
message: str,
code: str = ErrorCode.INTERNAL_ERROR.value,
status: int = 500,
detail: Optional[Dict[str, Any]] = None,
):
super().__init__(message)
self.message = message
self.code = code
self.status = status
self.detail = detail or {}
def to_dict(self) -> Dict[str, Any]:
"""Serialize to contract JSON."""
return {
"ok": False,
"error": self.message, # Legacy field
"code": self.code,
"message": self.message,
"detail": self.detail,
}
def to_response(error: APIError) -> Any:
"""
Convert APIError to aiohttp.web.Response.
Gracefully handles missing aiohttp by returning dict (for tests/fallback).
"""
payload = error.to_dict()
if web is not None:
return web.json_response(payload, status=error.status)
# Fallback for environments without aiohttp (e.g. some unit tests)
return payload
def create_error_response(
message: str,
code: str = ErrorCode.INTERNAL_ERROR.value,
status: int = 500,
detail: Optional[Dict[str, Any]] = None,
) -> Any:
"""Helper to create a response directly without raising."""
err = APIError(message, code, status, detail)
return to_response(err)