gohugoio/hugo · error
the seed value ( ) must be a non-negative integer
Error message
the seed value (%v) must be a non-negative integer
What it means
Thrown by Namespace.D — Hugo's sorted-unique-random-integer generator (Vitter's Method D) — when the `seed` argument fails to convert to int64 or is negative. The PRNG is seeded with this value, so it must be a deterministic non-negative integer; negatives and non-numeric values are rejected outright at validation time before any sampling occurs.
Solutions
- Pass an explicit non-negative integer literal, e.g. `D 42 3 10`.
- If the seed is computed, clamp it: `{{ $seed := mod $hash 1000000 }}` to guarantee non-negativity.
- Verify the seed variable is an int and not nil before calling D.
- Check upstream data sources (front matter, JSON) that feed the seed are numeric.
Example fix
// before
{{ $r := collections.D -1 3 10 }}
// after
{{ $r := collections.D 42 3 10 }} Defensive patterns
Strategy: validation
Validate before calling
func validateDSeed(seed any) (int64, error) {
s, err := cast.ToInt64E(seed)
if err != nil || s < 0 {
return 0, fmt.Errorf("seed must be non-negative int, got %v", seed)
}
return s, nil
} Type guard
func isNonNegInt(v any) bool {
n, err := cast.ToInt64E(v)
return err == nil && n >= 0
} Prevention
- Pass an explicit non-negative integer seed literal.
- Clamp computed seeds modulo a positive modulus before calling D.
- Verify seed is non-nil and numeric in partial preconditions.
- Avoid sourcing seeds from operations that can yield negatives (e.g. subtraction).
When it happens
Trigger: Calling `{{ partial "D" (dict "seed" -5 "n" 3 "hi" 10) }}` or the namespaced `collections.D` with a negative seed, a float like `1.5`, a string that cast cannot parse, or nil. The check is `cast.ToInt64E(seed)` returning an error OR seedInt < 0.
Common situations: Content author computes a seed from a date/hash that can be negative, passes a template variable that is unexpectedly nil or a string, or copies example code that hard-coded a seed which was later changed. Also seen when seeding from `math/rand` output cast improperly.
Related errors
- the maximum requested value
- the number of requested values
- arguments must be slices or arrays
- arguments to complement must be slices or arrays
- arguments to symdiff must be slices or arrays
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/da72a7c95b30cab7.
Report an issue: GitHub.
Appendix: source
Thrown at tpl/collections/collections.go:558
// D returns a sorted slice of unique random integers in the half-open interval
// [0, hi) using the provided seed value. The number of elements in the
// resulting slice is n or hi, whichever is less.
//
// If n <= hi, it returns a sorted random sample of size n using J. S. Vitter’s
// Method D for sequential random sampling.
//
// If n > hi, it returns the full, sorted range [0, hi) of size hi.
//
// If n == 0 or hi == 0, it returns an empty slice.
//
// Reference:
//
// J. S. Vitter, "An efficient algorithm for sequential random sampling," ACM Trans. Math. Softw., vol. 11, no. 1, pp. 37–57, 1985.
// See also: https://getkerf.wordpress.com/2016/03/30/the-best-algorithm-no-one-knows-about/
func (ns *Namespace) D(seed, n, hi any) ([]int, error) {
seedInt, err := cast.ToInt64E(seed)
if err != nil || seedInt < 0 {
return nil, fmt.Errorf("the seed value (%v) must be a non-negative integer", seed)
}
nInt, err := cast.ToIntE(n)
if err != nil || nInt < 0 || nInt > maxSeqSize {
return nil, fmt.Errorf("the number of requested values (%v) must be a non-negative integer <= %d", n, maxSeqSize)
}
hiInt, err := cast.ToIntE(hi)
if err != nil || hiInt < 0 || hiInt > maxSeqSize {
return nil, fmt.Errorf("the maximum requested value (%v) must be a non-negative integer <= %d", hi, maxSeqSize)
}
if nInt == 0 || hiInt == 0 {
return []int{}, nil
}
key := dKey{seed: uint64(seedInt), n: nInt, hi: hiInt}
View on GitHub (pinned to 52c9bd7908)