Source code for rath.errors
"""Stable machine-readable errors for OpenRath v2 public contracts."""
from __future__ import annotations
from collections.abc import Mapping
from enum import Enum
from typing import Any
from rath._json import JSONValue, freeze_mapping, thaw_json
__all__ = ["ErrorCode", "RathError"]
[docs]
class ErrorCode(str, Enum):
"""Stable error identifiers; enum values are part of the public API."""
INVALID_ARGUMENT = "request.invalid_argument"
UNAUTHENTICATED = "security.unauthenticated"
FORBIDDEN = "security.forbidden"
APPROVAL_REQUIRED = "security.approval_required"
POLICY_ERROR = "security.policy_error"
CONFLICT = "resource.conflict"
NOT_FOUND = "resource.not_found"
DEADLINE_EXCEEDED = "runtime.deadline_exceeded"
CANCELLED = "runtime.cancelled"
UNAVAILABLE = "runtime.unavailable"
INTERNAL = "internal.error"
[docs]
class RathError(RuntimeError):
"""Base exception with a stable code and serialization contract."""
def __init__(
self,
code: ErrorCode,
message: str,
*,
retryable: bool = False,
details: Mapping[str, object] | None = None,
) -> None:
if not message:
raise ValueError("message must not be empty")
super().__init__(message)
self.code = code
self.message = message
self.retryable = bool(retryable)
self.details: Mapping[str, JSONValue] = freeze_mapping(
details,
field="details",
)
[docs]
def to_dict(self) -> dict[str, Any]:
"""Return the stable transport representation."""
return {
"code": self.code.value,
"message": self.message,
"retryable": self.retryable,
"details": thaw_json(self.details),
}