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
- Fix the code that Puts a non-*rand.Rand object into globalRngPool
- Ensure the put path always stores the same concrete type obtained from the package's own factory
- 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
- Typed round-trip tests for the pool
- Never Put foreign types
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
- Unable to merge queue slice of type %T with type %T
- Unable to compact queue slice of type %T with type %T
- Current cluster name is empty
- Version increment <= 0 or > 2147483647
- <dynamic updateVersionToClusterName err>
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/1f62b931d0b4a731.
Report an issue: GitHub.