temporalio/temporal · error

Failed to access valid object from globalRngPool

Error message

Failed to access valid object from globalRngPool

What it means

fastrand maintains a pool of *rand.Rand objects; getRng retrieves one and asserts the type. If the pooled object is not a *rand.Rand — which can only happen if something Put an invalid object into the pool — the code panics, since continuing would corrupt all randomness-based behavior.

Source

Thrown at common/fastrand/fastrand.go:30

// globalRngPool is a globally shared object for allowing lock-free reuse
// of shared random number generators. In practice we would not expect this
// pool to contain many more objects than the number of CPU cores running
// the code.
var globalRngPool = sync.Pool{
	New: func() any {
		return rand.New(rand.NewSource(rand.Int63()))
	},
}

// getRng returns a thread-local [math/rand.Rand] object, largely a wrapper
// for globalRngPool.Get(), with a typecast and assertion that everything is
// as expected.
func getRng() *rand.Rand {
	rng, ok := globalRngPool.Get().(*rand.Rand)
	if !ok {
		// nolint:forbidigo
		panic("Failed to access valid object from globalRngPool") // This should never happen, since it would mean someone put an invalid object into the pool.
	}

	return rng
}

// Rand is an object that behaves largely as-if it was a [math/rand.Rand],
// with the key distinction that it is thread-safe and highly performant.
//
// Under the hood this uses a thread-safe pool of [math/rand.Rand] objects
// which it will dynamically create and access for each call. As a result,
// this does not support setting the seed, since the underlying objects
// are ephemeral.
type Rand struct{}

// ExpFloat64 implements [math/rand.Rand.ExpFloat64].
func (r Rand) ExpFloat64() float64 {
	rng := getRng()
	res := rng.ExpFloat64()

View on GitHub (pinned to bde624efd1)

Solutions

  1. Fix the code that Puts a non-*rand.Rand object into globalRngPool
  2. Ensure the put path always stores the same concrete type obtained from the package's own factory
  3. Add a test asserting pool round-trip type integrity

Example fix

// before
globalRngPool.Put(someOtherRng)
// after
globalRngPool.Put(rng) // rng must be *rand.Rand from the package's constructor
Defensive patterns

Strategy: type-guard

Type guard

rng, ok := v.(*rand.Rand)

Prevention

When it happens

Trigger: Essentially never from normal use: it requires code to Put a non-*rand.Rand value into globalRngPool. Practically triggered only by edits to the fastrand package itself or tests that tamper with the pool.

Common situations: A developer modifies the pool (adds a differently-typed object, wraps the pool, or changes the put-side type) and a subsequent Int/Float64/etc. call panics; nil pointer stored via a bad Put.

Related errors


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