Repository navigation
Add FailureDetails.is_caused_by() to mirror .NET's TaskFailureDetails.IsCausedBy<T>() #162
Description
Summary
The .NET SDK exposes TaskFailureDetails.IsCausedBy<T>() / IsCausedBy(Type), which lets a caller introspect an orchestration/activity failure and ask "was this caused by exception type T?" (with base-type support). The Python FailureDetails (durabletask/task.py) exposes message, error_type, and stack_trace, but has no equivalent introspection helper — callers must compare failure_details.error_type against a type name string by hand.
This is a general-purpose gap in the Python SDK's failure-introspection surface, not specific to any one feature.
Background / motivation
This came up during the scheduled-tasks PR (#160). The schedule client surfaces entity-side failures (e.g. an invalid state transition) as a generic RuntimeError carrying the failure message — which matches the current .NET ScheduledTasks client behavior (it throws a generic InvalidOperationException with FailureDetails.ErrorMessage). A more Pythonic API would let callers do something like:
try:
schedule_client.pause()
except OrchestrationError as e:
if e.failure_details.is_caused_by(ScheduleInvalidTransitionError):
...But the building block for that — failure-type introspection — doesn't exist yet. Rather than special-case it in the scheduled-tasks client, the framework primitive should land first.
Proposed API
Add to durabletask.task.FailureDetails:
def is_caused_by(self, error_type: str | type) -> bool:
"""Return True if this failure's error_type matches `error_type`.
Accepts either an exception type or its (qualified or unqualified) name.
"""Design notes / open questions:
- .NET matches by attempting to load the type named in
ErrorTypeand checking assignability (base-type aware). Python could do something analogous (import the type and useissubclass), or a simpler/safer name-based match. Worth deciding how much "load arbitrary type by name" behavior we want, given the security posture of the rest of the SDK. - Python's
error_typeis the bare class name (e.g.ScheduleInvalidTransitionError), not namespace-qualified like .NET, so a name-based comparison is straightforward but won't disambiguate same-named types from different modules. - Should this also consider
InnerFailure/chained causes once nested failure details are exposed?
Related
- PR Add scheduled tasks feature and delayed entity signals #160 (scheduled tasks) — discussion thread on flattening typed schedule exceptions to
RuntimeError. - .NET reference:
src/Abstractions/TaskFailureDetails.cs.
Out of scope
Reconstructing fully-typed exceptions (e.g. re-raising ScheduleInvalidTransitionError with its structured fields) is a separate, larger concern — the structured fields don't survive the orchestration boundary today (only the formatted message does), so that would need an additional from_failure(message)-style constructor convention. This issue is only about the is_caused_by introspection primitive.
Activity
Add FailureDetails.is_caused_by() and fully-qualified error types (#194)