"""Domain error types for ContextEngine.
Phase 0 frozen — specific exceptions enable precise error handling.
All errors inherit from standard Exception for compatibility.
"""
class ContextEngineError(Exception):
"""Base exception for all ContextEngine errors."""
pass
class AccessDeniedError(ContextEngineError):
"""Access control violation.
Raised when RequestContext.account_id does not match URI account prefix.
Also raised for unauthorized cross-agent or user-space access.
"""
def __init__(self, uri: str, account_id: str, reason: str = ""):
self.uri = uri
self.account_id = account_id
self.reason = reason
message = f"Access denied to {uri} for account {account_id}"
if reason:
message += f": {reason}"
super().__init__(message)
class NodeNotFoundError(ContextEngineError):
"""Requested node does not exist or is not ACTIVE.
Distinguished from HTTP 404 — node may exist but be PENDING/BROKEN.
"""
def __init__(self, uri: str):
self.uri = uri
super().__init__(f"Node not found or not ACTIVE: {uri}")
class NodeBrokenError(ContextEngineError):
"""Node exists but is in BROKEN state.
Indicates Repair Job detected corruption requiring manual intervention.
"""
def __init__(self, uri: str):
self.uri = uri
super().__init__(f"Node is BROKEN: {uri}")
class OutboxError(ContextEngineError):
"""Outbox processing failure.
Raised by OutboxWorker when event processing exceeds retry limit.
Event is moved to DLQ (dead letter queue).
"""
def __init__(self, event_id: str, reason: str):
self.event_id = event_id
self.reason = reason
super().__init__(f"Outbox event {event_id} failed: {reason}")
class MergePolicyError(ContextEngineError):
"""Merge policy evaluation failure.
Raised when MergePolicy cannot determine a valid WritePlan.
"""
def __init__(self, candidate_uri: str, reason: str):
self.candidate_uri = candidate_uri
self.reason = reason
super().__init__(f"Merge policy failed for {candidate_uri}: {reason}")
class EmbeddingError(ContextEngineError):
"""Embedding generation failure.
Raised when Embedder fails to produce vectors.
"""
def __init__(self, text_preview: str, reason: str):
self.text_preview = text_preview[:100]
self.reason = reason
super().__init__(f"Embedding failed for '{text_preview[:50]}...': {reason}")
class VectorIndexError(ContextEngineError):
"""Vector index operation failure.
Raised when VectorIndex upsert/delete/search fails.
"""
def __init__(self, operation: str, reason: str):
self.operation = operation
self.reason = reason
super().__init__(f"Vector index {operation} failed: {reason}")
class ValidationError(ContextEngineError):
"""Schema or validation failure.
Raised when input does not match expected schema.
"""
def __init__(self, field: str, reason: str):
self.field = field
self.reason = reason
super().__init__(f"Validation failed for {field}: {reason}")
class ConcurrentModificationError(ContextEngineError):
"""Optimistic lock failure during concurrent merge.
Raised when a merge write detects that the node was modified
between read and write (version mismatch).
Indicates the operation should be retried with fresh data.
"""
def __init__(self, uri: str, expected_version: int, actual_version: int):
self.uri = uri
self.expected_version = expected_version
self.actual_version = actual_version
super().__init__(
f"Concurrent modification detected for {uri}: "
f"expected version {expected_version}, found {actual_version}"
)
class RetrievalError(ContextEngineError):
"""Base exception for retrieval pipeline failures."""
def __init__(self, stage: str, reason: str, *, retryable: bool = False):
self.stage = stage
self.reason = reason
self.retryable = retryable
super().__init__(f"Retrieval [{stage}] failed: {reason}")
class RetrievalPlannerError(RetrievalError):
"""Query planner could not classify the query."""
def __init__(self, reason: str):
super().__init__("planner", reason)
class RetrievalSearchError(RetrievalError):
"""Vector search or hierarchical expansion failed."""
def __init__(self, reason: str, *, retryable: bool = True):
super().__init__("search", reason, retryable=retryable)