ExponentialRetryPolicy without maximum interval returns a ~292-year backoff on arm64 when the interval overflows
What are you really trying to do?
Use backoff.NewExponentialRetryPolicy (the Retrier path in common/backoff/retrypolicy.go) with the maximum interval cleared (NoInterval) and rely on the documented behavior that retries stop when the computed interval overflows.
Describe the bug
nextInterval is computed as float64; with maximumInterval == NoInterval and expirationInterval == NoInterval it can exceed MaxInt64 nanoseconds, and Go's conversion of an out-of-range float64 to time.Duration is platform-dependent:
- amd64: wraps negative, which is accidentally caught by the
nextDuration < p.initialIntervalcheck and returnsdone— matching the code comment ("Disallow retries ... if nextInterval overflows"). - arm64: saturates to
MaxInt64, soNextBackOffreturns2562047h47m16.8s(~292 years) and the retrier effectively waits forever.
This is the same bug class as #11225 fixed for ExponentialBackoffAlgorithm in common/backoff/retry.go; the Retrier/retrypolicy.go path never received that fix. Severity is honestly latent: no in-tree production caller currently clears the maximum interval, but the API allows it and behavior silently diverges by architecture.
Minimal Reproduction
On arm64, a unit test driving an uncapped policy past the overflow point expects done (-1ns) and observes 2562047h47m16.854775807s on main (706e0b4).
Environment/Versions
- Temporal Version: main (
706e0b4) - darwin/arm64 (bug manifests on arm64; amd64 accidentally behaves as documented)
I will submit a PR that explicitly returns done when the computed interval reaches MaxInt64, making both platforms follow the documented intent; capped policies are unaffected.
Source: temporalio/temporal