Source code for fastrag.exceptions
"""Exception hierarchy.
Every error raised by the SDK derives from :class:`FastragError`, so a caller
can catch the whole package with one ``except``. :class:`TransientError` is a
mixin rather than a branch of the tree, so an exception can be both typed by
origin — a fetch failure, an embedding failure — and marked retryable.
:func:`describe_error` is the counterpart for *reporting* one: not every
exception that reaches a failure handler is one of ours, and a third-party
exception raised with no arguments formats as an empty string.
"""
from __future__ import annotations
[docs]
class FastragError(Exception):
"""Base class for every error raised by Fastrag."""
[docs]
class TransientError(FastragError):
"""Mixin marking an error worth retrying.
Only exceptions carrying this mixin are retried by :class:`~fastrag.ingestion.policy.Policy`:
a timeout is transient, a malformed document is not.
"""
[docs]
class ConfigurationError(FastragError):
"""Invalid arguments, a missing optional dependency, or a bad template.
Always raised as early as possible — at construction, not at first use.
"""
[docs]
class SourceError(FastragError):
"""A source could not be turned into documents."""
[docs]
class FetchError(SourceError):
"""A resource could not be fetched."""
[docs]
class TransientFetchError(FetchError, TransientError):
"""A fetch failed for a reason that may succeed on retry (network, 5xx)."""
[docs]
class ParseError(SourceError):
"""A resource could not be parsed."""
[docs]
class TransientParseError(ParseError, TransientError):
"""Parsing failed because of a temporary model or network failure."""
[docs]
class ChunkingError(FastragError):
"""A document could not be chunked."""
[docs]
class ServiceError(FastragError):
"""A client for something outside the process failed."""
[docs]
class EmbeddingError(ServiceError):
"""An embedding request failed."""
[docs]
class TransientEmbeddingError(EmbeddingError, TransientError):
"""An embedding failed for a reason that may succeed on retry."""
[docs]
class ChatError(ServiceError):
"""A chat completion request failed."""
[docs]
class TransientChatError(ChatError, TransientError):
"""A chat completion failed for a reason that may succeed on retry."""
[docs]
class ContextLengthError(ChatError):
"""The prompt exceeded the model's context window.
Deliberately **not** a :class:`TransientError`: retrying an over-long
prompt produces the same failure, so ``Policy`` must not retry it.
"""
[docs]
class RerankError(ServiceError):
"""A rerank request failed."""
[docs]
class TransientRerankError(RerankError, TransientError):
"""A rerank failed for a reason that may succeed on retry."""
[docs]
class VectorStoreError(ServiceError):
"""A vector store operation failed."""
[docs]
class TransientVectorStoreError(VectorStoreError, TransientError):
"""A vector store operation failed for a reason that may succeed on retry."""
[docs]
class CacheError(FastragError):
"""The step cache could not be read or written."""
[docs]
class TransientCacheError(CacheError, TransientError):
"""A cache operation failed on lock contention or a lost connection."""
[docs]
class ChatStoreError(FastragError):
"""A chat store operation (session, chat, or message) could not be completed."""
[docs]
class TransientChatStoreError(ChatStoreError, TransientError):
"""A chat store operation failed on lock contention or a lost connection."""
[docs]
def describe_error(error: BaseException) -> str:
"""Format ``error`` for a human, never as an empty string.
``f"{error}"`` is the obvious way to render the ``error`` on an
:class:`~fastrag.ingestion.events.ItemFailed` or
:class:`~fastrag.ingestion.events.StepFailed`, and it renders an
exception raised with no arguments — ``TimeoutError()``,
``asyncio.CancelledError()``, a bare third-party sentinel — as nothing at
all, turning a real failure into a blank line. This falls back to the
exception's type name in that case, and prefixes it otherwise, so a
failure always says at minimum *what kind* of failure it was.
.. code-block:: python
describe_error(TimeoutError()) # -> "TimeoutError"
describe_error(ParseError("bad xlsx")) # -> "ParseError: bad xlsx"
Args:
error: The exception to describe.
Returns:
``"<type>: <message>"``, or just ``"<type>"`` when the exception
carries no message.
"""
message = str(error).strip()
name = type(error).__name__
return f"{name}: {message}" if message else name