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
ErrorType and checking assignability (base-type aware). Python could do something analogous (import the type and use issubclass), 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_type is 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
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.
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 typeT?" (with base-type support). The PythonFailureDetails(durabletask/task.py) exposesmessage,error_type, andstack_trace, but has no equivalent introspection helper — callers must comparefailure_details.error_typeagainst 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
RuntimeErrorcarrying the failure message — which matches the current .NET ScheduledTasks client behavior (it throws a genericInvalidOperationExceptionwithFailureDetails.ErrorMessage). A more Pythonic API would let callers do something like: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:Design notes / open questions:
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.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.InnerFailure/chained causes once nested failure details are exposed?Related
RuntimeError.src/Abstractions/TaskFailureDetails.cs.Out of scope
Reconstructing fully-typed exceptions (e.g. re-raising
ScheduleInvalidTransitionErrorwith 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 additionalfrom_failure(message)-style constructor convention. This issue is only about theis_caused_byintrospection primitive.