hashicorp/nomad · error
bug: users pool max must be >= min
Error message
bug: users pool max must be >= min
What it means
New enforces that PoolConfig.MaxUGID >= MinUGID; an inverted or empty-negative range is a caller bug and panics. The pool draws random UGIDs from [MinUGID, MaxUGID], which must be a valid ordered range.
Source
Thrown at helper/users/dynamic/pool.go:85
// indicating the client should not enable the dynamic workload users
// functionality
func (p *PoolConfig) disable() bool {
return p.MinUGID == doNotEnable || p.MaxUGID == doNotEnable
}
// New creates a Pool with the given PoolConfig options.
func New(opts *PoolConfig) Pool {
if opts == nil {
panic("bug: users pool cannot be nil")
}
if opts.disable() {
return new(noopPool)
}
if opts.MinUGID < 0 {
panic("bug: users pool min must be >= 0")
}
if opts.MaxUGID < opts.MinUGID {
panic("bug: users pool max must be >= min")
}
// a small but reasonable number of tasks to expect
const defaultPoolCapacity = 32
return &pool{
min: UGID(opts.MinUGID),
max: UGID(opts.MaxUGID),
lock: new(sync.Mutex),
used: set.New[UGID](defaultPoolCapacity),
}
}
// noopPool is an implementation of Pool that does not allow acquiring ugids
type noopPool struct{}
func (*noopPool) Restore(UGID) {}
func (*noopPool) Acquire() (UGID, error) {
return 0, errors.New("dynamic workload users disabled")
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Ensure MaxUGID >= MinUGID in the PoolConfig before calling New
- Validate config input (or clamp/swaps) when loading from user-facing configuration
- Add a unit test around pool construction to catch inverted ranges early
Example fix
// before
cfg := &dynamic.PoolConfig{MinUGID: 200_000, MaxUGID: 100_000} // swapped
// after
cfg := &dynamic.PoolConfig{MinUGID: 100_000, MaxUGID: 200_000} Defensive patterns
Strategy: validation
Validate before calling
if cfg != nil && cfg.MaxUGID < cfg.MinUGID { return fmt.Errorf("MaxUGID (%d) must be >= MinUGID (%d)", cfg.MaxUGID, cfg.MinUGID) } Try / catch
defer func() { if r := recover(); r != nil { if s, ok := r.(string); ok && strings.Contains(s, "users pool max must be >= min") { log.Fatalf("inverted UGID range: %v", s) }; panic(r) } }() Prevention
- Validate the range ordering before constructing PoolConfig
- Keep range values in named constants to avoid field-order mistakes
- Add a constructor wrapper in your codebase that normalizes min/max ordering
When it happens
Trigger: Calling users/dynamic.New with MaxUGID less than MinUGID, e.g. swapped values or a range that collapses below min.
Common situations: Swapped order of struct fields when constructing PoolConfig, config where an operator set a smaller max than min, or computed ranges where MaxUGID was adjusted downward below min.
Related errors
- bug: users pool min must be >= 0
- Reschedule policy has unlimited attempts enabled and a low d
- Lock delay and TTL must be positive
- failed to lookup task group %q
- https_handshake_timeout must be >= 0
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/2f565a0e41f628c2.
Report an issue: GitHub.