juanfont/headscale · error

getting random IP: %w

Error message

getting random IP: %w

What it means

Inside allocateNext, when the strategy is IPAllocationStrategyRandom the start address is chosen by randomNext(). This error wraps a failure of that call — the crypto/rand-based pick of a random offset inside the prefix could not be completed.

Source

Thrown at hscontrol/db/ip.go:197

	*prev = *ret

	return ret, nil
}

func (i *IPAllocator) next(prev netip.Addr, prefix *netip.Prefix) (*netip.Addr, error) {
	var (
		err error
		ip  netip.Addr
	)

	switch i.strategy {
	case types.IPAllocationStrategySequential:
		// Get the first IP in our prefix
		ip = prev.Next()
	case types.IPAllocationStrategyRandom:
		ip, err = randomNext(*prefix)
		if err != nil {
			return nil, fmt.Errorf("getting random IP: %w", err)
		}
	}

	// TODO(kradalby): maybe this can be done less often.
	set, err := i.usedIPs.IPSet()
	if err != nil {
		return nil, err
	}

	// Walk forward from the starting address until a free, non-reserved
	// address inside the prefix is found. The random strategy only picks the
	// starting point at random and then scans deterministically: this keeps
	// the loop finite, so an exhausted prefix returns ErrCouldNotAllocateIP
	// instead of re-drawing in-prefix addresses forever under i.mu.
	start := ip
	for {
		if prefix.Contains(ip) && !set.Contains(ip) && !isTailscaleReservedIP(ip) {
			i.usedIPs.Add(ip)

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Switch ip_allocation_strategy to sequential — deterministic and avoids the entropy path entirely.
  2. Fix the environment's entropy: ensure /dev/urandom is available and not blocked by the container runtime/seccomp.
  3. Check dmesg/kernel logs for RNG initialization failures on the host.

Example fix

# before (config.yaml)
ip_allocation_strategy: random

# after
ip_allocation_strategy: sequential
Defensive patterns

Strategy: fallback

Validate before calling

// Environment pre-check for the random strategy:
// cat /proc/sys/kernel/random/entropy_avail  # expect > 128
// Or in Go: read 16 bytes from crypto/rand and time it.

Try / catch

// Catch and fall back to sequential allocation for that request:
//   ip, err := alloc.Next()
//   if err != nil && strings.Contains(err.Error(), "getting random IP") {
//       ip, err = sequentialAlloc.Next() // or reconfigure strategy and retry
//   }

Prevention

When it happens

Trigger: rand.Int(rand.Reader, ...) failing (error 418's cause: entropy source error), or — via the chained error — the generated address failing prefix containment checks. Reached only when ip_allocation_strategy is set to random.

Common situations: Containers/VMs with a depleted or blocked entropy source (/dev/random blocking in restricted environments); rare in modern kernels, more common in minimal chroots or certain seccomp profiles.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/567efabbfffad175. Report an issue: GitHub.