mirror of
https://github.com/temporalio/temporal.git
synced 2026-08-30 18:41:49 -07:00
## What changed? `handleStartOperationError` (`components/nexusoperations/executors.go`), `callErrorToFailure`, and `newInvocationResult` (`chasm/lib/nexusoperation/task_handler_helpers.go`) all unwrap `callErr` into a typed `serviceerror.ServiceError` via `errors.As`/`errors.AsType`, then pass the *original wrapped* `callErr` — not the unwrapped `serviceErr` — to `common.IsRetryableRPCError`. Fix: pass the already-unwrapped `serviceErr` to `IsRetryableRPCError` at all three call sites — in both the workflow-based (`components/nexusoperations`) and CHASM standalone (`chasm/lib/nexusoperation`) Nexus operation state machines. These were the only call sites of `IsRetryableRPCError` outside its own definition/tests. ## Why? `IsRetryableRPCError` only recognizes a service error via a direct (non-unwrapping) type assertion or a gRPC status; neither sees through wrapping. So whenever the transport wraps the service error (e.g. `net/http.Client.Do` wraps `RoundTripper` errors in `*url.Error`), a transient error like `Unavailable` is always misclassified as non-retryable, permanently failing the Nexus operation instead of retrying it. Observed in practice: a Nexus `cancel` operation dispatched during a brief window where the internal service resolver had zero available frontend members failed with `Unavailable: no frontend host to route request to`. That error was wrapped by the HTTP round-tripper, misclassified as non-retryable, and permanently failed the operation — with ~19 of its 20-minute `scheduleToCloseTimeout` still unused, while sibling operations dispatched moments later succeeded normally. A single retry would have resolved it. ## How did you test it? - [x] built - [ ] run locally and tested manually - [x] covered by existing tests - [x] added new unit test(s) - [ ] added new functional test(s) ## Potential risks Low risk: the change only affects the retryability decision for the `serviceerror` branch of Nexus start-operation error handling, and only for errors that were previously misclassified (wrapped service errors). Correctly-classified cases (direct/unwrapped service errors, gRPC status errors) are unaffected since `serviceErr` and `callErr` resolve to the same classification for those.