💥 Use Temporal Failures for Nexus Error Serialization#1336
💥 Use Temporal Failures for Nexus Error Serialization#1336Quinn-With-Two-Ns wants to merge 2 commits intomainfrom
Conversation
| keywords = ["temporal", "workflow"] | ||
| dependencies = [ | ||
| "nexus-rpc==1.3.0", | ||
| "nexus-rpc", |
There was a problem hiding this comment.
Unpinned dependency and development git source for nexus-rpc
High Severity
The nexus-rpc dependency was changed from ==1.3.0 to a bare "nexus-rpc" with no version constraint, and a [tool.uv.sources] git override pointing to a feature branch (amazzeo/add-failure) was added. The git source only applies to uv-based installs; pip users installing the published package would resolve nexus-rpc from PyPI with no version floor, potentially getting an old version that lacks the new failure serialization APIs. Every other dependency in the list has version bounds. The version constraint needs to be restored with appropriate bounds, and the [tool.uv.sources] development override needs to be removed before merge.
Additional Locations (1)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b58ce8660f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| keywords = ["temporal", "workflow"] | ||
| dependencies = [ | ||
| "nexus-rpc==1.3.0", | ||
| "nexus-rpc", |
There was a problem hiding this comment.
Pin nexus-rpc to a version that supports new failure fields
This change removes the explicit nexus-rpc==1.3.0 requirement while the new converter path now constructs nexusrpc.HandlerError with stack_trace/original_failure (see DefaultFailureConverter.from_failure), which are not guaranteed on older releases. In environments that install from PyPI (which ignore [tool.uv.sources]), resolving to an incompatible nexus-rpc version will raise runtime TypeError the first time a Nexus handler failure is decoded, so this dependency needs a minimum/compatible version constraint.
Useful? React with 👍 / 👎.
| match err.state: | ||
| case nexusrpc.OperationErrorState.CANCELED: | ||
| raise CancelledError(err.message) from err.__cause__ | ||
| case nexusrpc.OperationErrorState.FAILED: | ||
| raise ApplicationError( |
There was a problem hiding this comment.
Handle unknown OperationError states explicitly
The match err.state block only raises for CANCELED and FAILED; there is no default branch. If an unexpected state is received (e.g., from a newer nexus-rpc enum value or a malformed custom raise), this except nexusrpc.OperationError path falls through without returning a StartOperationResponse, and _handle_start_operation_task proceeds as if start-operation succeeded with an invalid empty response variant instead of surfacing a failure.
Useful? React with 👍 / 👎.


Note This PR can't be merged until the corresponding Core PR (temporalio/sdk-core#1109) is merged and updated in this branch and the nexus-rpc PR (nexus-rpc/sdk-python#45) is merged and released
What was changed
nexus.v1.Failurewith metadata/details), Nexus handler errors and operation errors are now serialized as standard Temporalfailure.v1.Failureprotos via the SDK'sDataConverter/FailureConverter. This includesHandlerError→nexus_handler_failure_infoandOperationError→CancelledError/ApplicationErrorconversions._nexus.pyworker code: Removed the_nexus_error_to_nexus_failure_proto,_operation_error_to_proto, and_handler_error_to_protohelper methods. Errors are now encoded directly throughdata_converter.encode_failure()into the completion/response proto'sfailurefield._exception_to_handler_error: Removed the workaround that inserted an extraApplicationErrorat the head of theHandlerErrorcause chain (previously needed to preserve theHandlerErrormessage when hoisted to the Nexus Failure)._error_to_failureforHandlerErrornow useserror.messageanderror.stack_traceinstead ofstr(error).from_failureusesmatch/caseinstead ofif/elifchains.nexus_pb2,workflow_activation_pb2,workflow_commands_pb2, and the sdk-core submodule to support the new Nexus failure fields on completion protos.test_handler.pyandtest_handler_async_operation.pywhich tested via direct HTTP calls (the HTTP interface is not user-facing). Converted remaining tests (test_workflow_run_operation.py,test_dynamic_creation_of_user_handler_classes.py) to use workflow callers.ErrorConversionTestCaseregistry pattern with typed dataclasses (ExpectedNexusOperationError,ExpectedHandlerError,ExpectedApplicationError,ExpectedCancelledError) and explicitErrorTestServicehandler methods.test_converter.pyfor round-trip serialization ofHandlerError,NexusOperationError,OperationError, and related types.self._interceptorsvariable in the Nexus worker.Why?
The previous Nexus error serialization used a custom JSON-based format (
nexus.v1.Failurewith metadata and JSON details) that was specific to the Nexus HTTP protocol. With the move to have Core SDK handle protocol-level conversion based on server capabilities, the Python SDK now only needs to produce standard Temporal Failure protos.Checklist
How was this tested:
FailureConverterround-trip serialization of Nexus error types intests/test_converter.pytests/nexus/test_workflow_caller_error_chains.pyAny docs updates needed?
Note
Medium Risk
Generated API/proto shape changes for Nexus responses can break consumers relying on the old
operation_errorvariant or missing new capability fields, and behavior depends on a non-releasednexus-rpcgit source override.Overview
Nexus protos are updated to support Temporal failure serialization by adding a new
StartOperationResponse.failurevariant of typetemporal.api.failure.v1.Failureand deprecating the olderoperation_errorvariant, plus extendingnexus.v1.Failurewithstack_traceand recursivecausefields.Adds
Request.Capabilities(includingtemporal_failure_responses) to allow capability negotiation, wires in the new failure proto dependency/imports in generated files, and exposesCountSchedulesRequest/Responsefromworkflowservice.v1.pyproject.tomlloosensnexus-rpcpinning and adds auvgit source override for a specificnexus-rpcbranch.Written by Cursor Bugbot for commit b58ce86. This will update automatically on new commits. Configure here.