Exception Handling¶
Victor uses the consolidated error hierarchy in victor.core.errors. Runtime
code should import concrete error classes from that module rather than defining
local exception hierarchies or importing deprecated framework shims.
Error Hierarchy¶
Use VictorError as the base for project errors. The common public categories
are:
ProviderErrorfor LLM provider failures.ToolErrorfor tool execution failures.ConfigurationErrorfor invalid or missing configuration.ValidationErrorfor invalid user or API input.FileErrorandNetworkErrorfor resource failures.
Specialized subclasses such as ProviderConnectionError,
ProviderRateLimitError, ToolExecutionError, and ToolValidationError
should be preferred when they describe the failure precisely.
Rules¶
- Catch the most specific Victor error type available.
- Preserve exception context with
raise ... from ewhen wrapping lower-level
exceptions. - Log with
exc_infoand structured context before re-raising. - Avoid bare
except:except for cleanup blocks that immediately re-raise. - Do not return
Noneor silently swallow failures that callers need to
handle. - Put new reusable error classes in
victor.core.errors.
Provider Pattern¶
import logging
from victor.core.errors import ProviderAuthError, ProviderConnectionError, ProviderError
logger = logging.getLogger(__name__)
async def call_provider(provider, messages):
try:
return await provider.chat(messages)
except ProviderAuthError:
logger.error("Provider authentication failed", exc_info=True, extra={"provider": provider.name})
raise
except ProviderConnectionError:
logger.error("Provider connection failed", exc_info=True, extra={"provider": provider.name})
raise
except ProviderError:
logger.error("Provider call failed", exc_info=True, extra={"provider": provider.name})
raise
Tool Pattern¶
import logging
from victor.core.errors import ToolExecutionError, ToolValidationError
logger = logging.getLogger(__name__)
async def run_tool(tool, args):
try:
return await tool.execute(**args)
except ToolValidationError:
logger.warning("Tool arguments are invalid", exc_info=True, extra={"tool": tool.name})
raise
except ToolExecutionError:
logger.error("Tool execution failed", exc_info=True, extra={"tool": tool.name, "args": args})
raise
Wrapping External Exceptions¶
from victor.core.errors import ProviderConnectionError
async def connect(provider_name, client):
try:
return await client.connect()
except OSError as e:
raise ProviderConnectionError(
"Failed to connect to provider",
provider=provider_name,
) from e
Anti-Patterns¶
Avoid generic catch-and-suppress logic:
try:
result = await provider.chat(messages)
except Exception as e:
logger.error(f"Error: {e}")
return None
Avoid losing the original cause:
Prefer the canonical hierarchy: