taskflow-api / src /core /exceptions.py
suhail
chatbot
676582c
raw
history blame
4.33 kB
"""
Custom exception classes for structured error handling.
"""
from typing import Optional
from fastapi import HTTPException, status
from src.schemas.error import ErrorCode
class AIProviderException(HTTPException):
"""Base exception for AI provider errors."""
def __init__(
self,
error_code: str,
detail: str,
status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR,
provider: Optional[str] = None
):
super().__init__(status_code=status_code, detail=detail)
self.error_code = error_code
self.source = "AI_PROVIDER"
self.provider = provider
class RateLimitExceededException(AIProviderException):
"""Exception raised when AI provider rate limit is exceeded."""
def __init__(self, provider: Optional[str] = None):
super().__init__(
error_code=ErrorCode.RATE_LIMIT_EXCEEDED,
detail="AI service rate limit exceeded. Please wait a moment and try again.",
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
provider=provider
)
class APIKeyMissingException(AIProviderException):
"""Exception raised when API key is not configured."""
def __init__(self, provider: Optional[str] = None):
super().__init__(
error_code=ErrorCode.API_KEY_MISSING,
detail="AI service is not configured. Please add an API key.",
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
provider=provider
)
class APIKeyInvalidException(AIProviderException):
"""Exception raised when API key is invalid or expired."""
def __init__(self, provider: Optional[str] = None):
super().__init__(
error_code=ErrorCode.API_KEY_INVALID,
detail="Your API key is invalid or expired. Please check your configuration.",
status_code=status.HTTP_401_UNAUTHORIZED,
provider=provider
)
class ProviderUnavailableException(AIProviderException):
"""Exception raised when AI provider is temporarily unavailable."""
def __init__(self, provider: Optional[str] = None):
super().__init__(
error_code=ErrorCode.PROVIDER_UNAVAILABLE,
detail="AI service is temporarily unavailable. Please try again later.",
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
provider=provider
)
class ProviderErrorException(AIProviderException):
"""Exception raised for generic AI provider errors."""
def __init__(self, detail: str, provider: Optional[str] = None):
super().__init__(
error_code=ErrorCode.PROVIDER_ERROR,
detail=detail,
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
provider=provider
)
def classify_ai_error(error: Exception, provider: Optional[str] = None) -> AIProviderException:
"""
Classify an AI provider error and return appropriate exception.
Args:
error: The original exception from the AI provider
provider: Name of the AI provider (gemini, openrouter, cohere)
Returns:
Appropriate AIProviderException subclass
"""
error_message = str(error).lower()
# Rate limit errors
if any(keyword in error_message for keyword in ["rate limit", "429", "quota exceeded", "too many requests"]):
return RateLimitExceededException(provider=provider)
# API key missing errors
if any(keyword in error_message for keyword in ["api key not found", "api key is required", "missing api key"]):
return APIKeyMissingException(provider=provider)
# API key invalid errors
if any(keyword in error_message for keyword in [
"invalid api key", "api key invalid", "unauthorized", "401",
"authentication failed", "invalid credentials", "api key expired"
]):
return APIKeyInvalidException(provider=provider)
# Provider unavailable errors
if any(keyword in error_message for keyword in [
"503", "service unavailable", "temporarily unavailable",
"connection refused", "connection timeout", "timeout"
]):
return ProviderUnavailableException(provider=provider)
# Generic provider error
return ProviderErrorException(
detail=f"AI service error: {str(error)}",
provider=provider
)