Skip to content

Errors

The framework's errors live in interloper.errors. The errors the platform's persistence raises, and its services map to responses, live in interloper_db.errors; both families subclass InterloperError.

Custom exception hierarchy for the Interloper framework.

All exceptions inherit from InterloperError, allowing users to catch any framework error with a single except InterloperError clause, or target specific domains (DAGError, ConfigError, etc.) for finer control.

Most domain exceptions also inherit the built-in they refine (e.g., DAGError(InterloperError, ValueError)), so existing except ValueError: handlers keep catching them.

Some validation raises built-ins directly: unknown constructor keyword arguments, a FetchField provider reference that does not resolve, an oauth= decorator option on a non-OAuth connection, and multiple discriminator fields raise TypeError; an invalid key or identifier, a window ending before it starts, an unsupported granularity, and bounded_gather(limit=0) raise ValueError; Registry[...] on a missing name raises KeyError. Binding a component a relation does not accept raises ConfigError instead.

InterloperError

Bases: builtins.Exception

Base exception for all Interloper framework errors.

ConfigError

Bases: interloper.errors.InterloperError, builtins.ValueError

A configuration value is missing, has the wrong type, or cannot be resolved.

SpecError

Bases: interloper.errors.ConfigError

A component spec document is invalid or cannot be loaded.

Raised on YAML parse failures, unresolved ${VAR} references, and malformed spec documents.

DAGError

Bases: interloper.errors.InterloperError, builtins.ValueError

An error in DAG construction or validation.

CircularDependencyError

Bases: interloper.errors.DAGError

A circular dependency was detected in the DAG.

AssetNotFoundError

Bases: interloper.errors.DAGError, builtins.KeyError

An asset key was not found in the DAG.

AssetError

Bases: interloper.errors.InterloperError, builtins.ValueError

An error in asset definition, configuration, or execution setup.

ConnectionCheckError

Bases: interloper.errors.InterloperError

A connection check failed with a curated, user-facing message.

Raised from Connection.check() implementations when the failure deserves a better message than the generic HTTP-error categorisation.

PartitionError

Bases: interloper.errors.ConfigError

A partitioning declaration, a partition key or a run's window is invalid.

SchemaError

Bases: interloper.errors.InterloperError, builtins.ValueError

An error in schema validation, reconciliation, or inference.

NormalizerError

Bases: interloper.errors.InterloperError, builtins.TypeError

The normalizer received data that is not list[dict].

RepresentationError

Bases: interloper.errors.InterloperError, builtins.TypeError

No registered representation matches the data's type.

DestinationError

Bases: interloper.errors.InterloperError

Base class for destination-related errors.

DataNotFoundError

Bases: interloper.errors.DestinationError

No data was found in the destination backend for the requested key.

EventError

Bases: interloper.errors.InterloperError, builtins.ValueError

An error in event deserialization or processing.

RunnerError

Bases: interloper.errors.InterloperError, builtins.RuntimeError

An error in runner orchestration or scheduling.

AuthenticationError

Bases: interloper.errors.InterloperError, builtins.ValueError

An authentication or token error in the REST client.

CatalogKeyError

Bases: interloper.errors.ConfigError

A component key was not found in the catalog.

Raised when a source, destination, or resource key referenced in the database does not match any registered component definition.

format_exception

format_exception(exception: BaseException) -> str

Format an exception as a non-empty, single-line error string.

str(exception) alone is empty for message-less exceptions (e.g. httpx2.ReadTimeout), which downstream consumers (event rows, run results, the UI) treat as "no error". Always lead with the type name so the error stays identifiable either way.

Pydantic's ValidationError never formats via str(): its string embeds each error's input_value, and for a sensitive model (e.g. a connection's decrypted payload) that would leak secrets into whatever carries the message. It collapses to field-and-reason lines instead.

Parameters:

Name Type Description Default
exception BaseException

The exception to format; any BaseException.

required

Returns:

Type Description
str

"TypeName: message", or just "TypeName" when the message is empty.

errors

Errors the platform's persistence raises and its services map to responses.

Each still subclasses the framework's InterloperError, so one except InterloperError catches them along with the framework's own.

NotFoundError

Bases: InterloperError, KeyError

A database record was not found.

Raised by the store layer; the API answers HTTP 404.

ConflictError

Bases: InterloperError, ValueError

A record's current state does not allow the requested operation.

Raised by the store layer for a request that was well-formed but arrived at the wrong moment (a run already terminal, a stack whose latest attempt did not fail); the API answers HTTP 409.

InUseError

InUseError(
    message: str,
    referrers: list[dict[str, str | None]] | None = None,
)

Bases: ConflictError

A record cannot be deleted because other records still reference it.

Raised by the store layer; the API answers HTTP 409 with the referrers. referrers carries the referencing records as {id, kind, key, name} mappings so callers can build structured error payloads.

Initialize with a user-facing message and the referencing records.

Parameters:

Name Type Description Default
message str

User-facing explanation of the conflict.

required
referrers list[dict[str, str | None]] | None

The referencing records as {id, kind, key, name} mappings; None is stored as an empty list.

None

QuotaExceededError

QuotaExceededError(
    message: str, *, quota: str, limit: int, used: int
)

Bases: InterloperError

An organisation quota does not allow the requested operation.

Raised by the store layer; API routes surface it as HTTP 429 with the structured fields so clients can show limit and usage.

Initialize with a user-facing message and the quota context.

Parameters:

Name Type Description Default
message str

User-facing explanation of the refusal.

required
quota str

Name of the exceeded quota (e.g. "max_sources").

required
limit int

The quota's limit.

required
used int

Usage already counted against the limit.

required

HydrationError

Bases: InterloperError

Failed to reconstruct a live object from a database record.

Raised when a stored spec, config, or resource cannot be deserialized back into its framework class (e.g. missing fields, unknown import path, validation failure).

ComponentDriftError

Bases: InterloperError

A persisted component references a catalog key that no longer resolves.

Raised when hydrating a stored source or asset whose catalog key has drifted: the underlying class was renamed or removed from the code (missing), or is not exposed by this deployment's catalog (disabled). Distinct from HydrationError (which signals a reconstruction failure for a key that does resolve) so callers and the API layer can treat drift as a recoverable, user-resolvable state rather than a hard failure.