temporalio/temporal · error

internal error: call to RetryLockedSource.Seed

Error message

internal error: call to RetryLockedSource.Seed

What it means

RetryLockedSource in common/backoff/retrypolicy.go is a math/rand.Source wrapper that is deliberately seeded once at construction (from time.Now().UnixNano()). Calling Seed on it afterwards would break retry-backoff determinism guarantees, so the method unconditionally panics with "internal error: call to RetryLockedSource.Seed". It marks an unsupported operation as a programmer error.

Source

Thrown at common/backoff/retrypolicy.go:339

// See the following discussions for details
// https://github.com/golang/go/issues/24121 <- main
// https://github.com/stripe/veneur/pull/466 -< make rng source faster
// https://github.com/golang/go/issues/25057
// https://github.com/golang/go/issues/21393

type RetryLockedSource struct {
	lk sync.Mutex
	s  rand.Source
}

func (r *RetryLockedSource) Int63() int64 {
	r.lk.Lock()
	defer r.lk.Unlock()
	return r.s.Int63()
}

func (r *RetryLockedSource) Seed(seed int64) {
	panic("internal error: call to RetryLockedSource.Seed")
}

func NewRetryLockedSource() *RetryLockedSource {
	return &RetryLockedSource{
		lk: sync.Mutex{},
		s:  rand.NewSource(time.Now().UnixNano()),
	}
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Remove the Seed call — RetryLockedSource is seeded automatically at NewRetryLockedSource()
  2. If deterministic seeding is needed, construct your own rand.NewSource(seed) instead of RetryLockedSource
  3. Audit code that accepts rand.Source to ensure it does not call Seed on the provided source

Example fix

// before
src := backoff.NewRetryLockedSource()
rnd := rand.New(src)
rnd.Seed(42) // panics
// after
src := rand.NewSource(42) // deterministic test source
rnd := rand.New(src)
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no code path calls Seed on a source you don't own:
if s, ok := src.(*backoff.RetryLockedSource); ok {
    _ = s // do not Seed; already seeded at construction
}

Prevention

When it happens

Trigger: Calling (r *RetryLockedSource).Seed(seed int64) directly, or passing a RetryLockedSource to code that calls Seed on any rand.Source (e.g. rand.New(source).Seed(...), some shuffling/seeding utilities).

Common situations: Reusing a backoff policy helper that reseeds its source for reproducibility in tests; generic code that takes a rand.Source interface and defensively seeds it; wiring RetryLockedSource into a rand.Rand and then calling Seed on the Rand.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/3800490bcac5bd08. Report an issue: GitHub.