Files
OpenViking/openviking_cli/exceptions.py
T
Qin Haojie a386269d38 fix(resources): 明确等待超时语义并改用任务轮询示例 (#4888)
等待超时返回任务 ID 和状态查询提示,避免误认为后台导入失败;主要文档和示例改为提交后查询任务状态。
2026-09-10 11:52:14 +08:00

226 lines
7.4 KiB
Python

# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd.
# SPDX-License-Identifier: AGPL-3.0
"""
Unified exception classes for OpenViking.
Based on gRPC standard status codes for consistency across service boundaries.
"""
from typing import Optional
class OpenVikingError(Exception):
"""Base exception for all OpenViking errors."""
def __init__(self, message: str, code: str = "UNKNOWN", details: Optional[dict] = None):
super().__init__(message)
self.message = message
self.code = code
self.details = details or {}
# ============= Argument Errors =============
class InvalidArgumentError(OpenVikingError):
"""Invalid argument provided."""
def __init__(self, message: str, details: Optional[dict] = None):
super().__init__(message, code="INVALID_ARGUMENT", details=details)
class InvalidURIError(InvalidArgumentError):
"""Invalid Viking URI format."""
def __init__(self, uri: str, reason: str = ""):
message = f"Invalid URI: {uri}"
if reason:
message += f" ({reason})"
super().__init__(message, details={"uri": uri, "reason": reason})
self.code = "INVALID_URI"
class UnsupportedDirectoryFilesError(InvalidArgumentError):
"""Directory contains unsupported file types (used when strict=True)."""
def __init__(self, message: str, unsupported_files: list):
super().__init__(message, details={"unsupported_files": unsupported_files})
self.unsupported_files = unsupported_files
# ============= Resource Errors =============
class NotFoundError(OpenVikingError):
"""Resource not found."""
def __init__(
self,
resource: str,
resource_type: str = "resource",
reason: Optional[str] = None,
):
details = {"type": resource_type}
if resource:
details["resource"] = resource
message = f"{resource_type.capitalize()} not found: {resource}"
else:
message = f"{resource_type.capitalize()} not found"
if reason:
details["reason"] = reason
message = f"{message}. {reason}"
super().__init__(message, code="NOT_FOUND", details=details)
class AlreadyExistsError(OpenVikingError):
"""Resource already exists."""
def __init__(self, resource: str, resource_type: str = "resource"):
message = f"{resource_type.capitalize()} already exists: {resource}"
super().__init__(
message, code="ALREADY_EXISTS", details={"resource": resource, "type": resource_type}
)
class ConflictError(OpenVikingError):
"""Resource conflict (e.g., locked by another operation)."""
def __init__(self, message: str, resource: Optional[str] = None):
details = {"resource": resource} if resource else {}
super().__init__(message, code="CONFLICT", details=details)
class FailedPreconditionError(OpenVikingError):
"""Operation cannot proceed because a required precondition is unmet."""
def __init__(self, message: str, details: Optional[dict] = None):
super().__init__(message, code="FAILED_PRECONDITION", details=details)
class AbortedError(OpenVikingError):
"""Operation was aborted, typically due to a concurrency conflict."""
def __init__(self, message: str = "Operation aborted", details: Optional[dict] = None):
super().__init__(message, code="ABORTED", details=details)
# ============= Authentication Errors =============
class UnauthenticatedError(OpenVikingError):
"""Authentication required but not provided or invalid."""
def __init__(self, message: str = "Authentication required"):
super().__init__(message, code="UNAUTHENTICATED")
class PermissionDeniedError(OpenVikingError):
"""Permission denied for the requested operation."""
def __init__(self, message: str = "Permission denied", resource: Optional[str] = None):
details = {"resource": resource} if resource else {}
super().__init__(message, code="PERMISSION_DENIED", details=details)
# ============= Service Errors =============
class UnavailableError(OpenVikingError):
"""Service temporarily unavailable."""
def __init__(self, service: str = "service", reason: str = ""):
message = f"{service.capitalize()} unavailable"
if reason:
message += f": {reason}"
super().__init__(
message, code="UNAVAILABLE", details={"service": service, "reason": reason}
)
class ResourceExhaustedError(OpenVikingError):
"""Resource quota, rate limit, or billing capacity was exhausted."""
def __init__(self, message: str = "Resource exhausted", details: Optional[dict] = None):
super().__init__(message, code="RESOURCE_EXHAUSTED", details=details)
class InternalError(OpenVikingError):
"""Internal server error."""
def __init__(self, message: str = "Internal error", cause: Optional[Exception] = None):
details = {"cause": str(cause)} if cause else {}
super().__init__(message, code="INTERNAL", details=details)
class DeadlineExceededError(OpenVikingError):
"""Operation timed out."""
def __init__(
self,
operation: str = "operation",
timeout: Optional[float] = None,
*,
task_id: Optional[str] = None,
):
message = f"{operation.capitalize()} timed out"
if timeout:
message += f" after {timeout}s"
details = {"operation": operation, "timeout": timeout}
if task_id is not None:
message += (
". This timeout only stops waiting; it does not cancel or fail the background task. "
f"Check its status with 'ov task status {task_id}'."
)
details["task_id"] = task_id
super().__init__(message, code="DEADLINE_EXCEEDED", details=details)
class UnimplementedError(OpenVikingError):
"""Operation is not implemented."""
def __init__(self, message: str = "Operation not implemented", details: Optional[dict] = None):
super().__init__(message, code="UNIMPLEMENTED", details=details)
# ============= Business Errors =============
class ProcessingError(OpenVikingError):
"""Error during resource processing."""
def __init__(self, message: str, source: Optional[str] = None):
details = {"source": source} if source else {}
super().__init__(message, code="PROCESSING_ERROR", details=details)
class EmbeddingFailedError(ProcessingError):
"""Embedding generation failed."""
def __init__(self, message: str = "Embedding generation failed", source: Optional[str] = None):
super().__init__(message, source=source)
self.code = "EMBEDDING_FAILED"
class VLMFailedError(ProcessingError):
"""VLM processing failed."""
def __init__(self, message: str = "VLM processing failed", source: Optional[str] = None):
super().__init__(message, source=source)
self.code = "VLM_FAILED"
class SessionExpiredError(OpenVikingError):
"""Session has expired."""
def __init__(self, session_id: str):
message = f"Session expired: {session_id}"
super().__init__(message, code="SESSION_EXPIRED", details={"session_id": session_id})
class NotInitializedError(OpenVikingError):
"""Service or component not initialized."""
def __init__(self, component: str = "service"):
message = f"{component.capitalize()} not initialized. Call initialize() first."
super().__init__(message, code="NOT_INITIALIZED", details={"component": component})