Skip to content

Cause-aware exceptions

DataExcept uses cause as the canonical keyword and public attribute for an underlying exception wrapped by an operational exception.

from dataexcept import StorageError

try:
    write_object()
except OSError as exc:
    raise StorageError(
        "s3://analytics/output.parquet",
        "write",
        cause=exc,
    ) from exc

When cause is supplied, DataExcept also sets __cause__. Tracebacks therefore preserve the underlying failure automatically, pickling preserves the chain, and exception_to_dict / exception_to_json expose the nested failure under the envelope's top-level cause field.

Backward compatibility

Classes that historically accepted original or original_exception keep those parameters. They are compatibility aliases and are mirrored to the canonical .cause attribute.

For example, both calls remain valid:

QueryExecutionError("SELECT 1", original=db_exc)
QueryExecutionError("SELECT 1", cause=db_exc)

ServiceConnectionError("warehouse", original_exception=network_exc)
ServiceConnectionError("warehouse", cause=network_exc)

Do not supply a canonical cause and a legacy alias in the same constructor call. DataExcept rejects that as ambiguous with TypeError.

Wrapping third-party failures

wrap() and wrapping() prefer the canonical cause keyword whenever the target constructor supports it, while continuing to support older exception classes that expose only original or original_exception.

from dataexcept import StorageError, wrapping

with wrapping(
    OSError,
    StorageError,
    location="/data/input.csv",
    operation="read",
):
    read_file()

DataExcept describes and preserves the cause. It does not decide whether the failure should be retried; retryability is a separate operational contract.