juanfont/headscale · error

generating random IP: %w

Error message

generating random IP: %w

What it means

randomNext picks a uniform random offset within the prefix using crypto/rand's rand.Int over the range size. This error means the system entropy source returned an error — the read from rand.Reader failed. Single-address prefixes (from == to) are short-circuited before this call, so this specifically signals an entropy/reader fault.

Source

Thrown at hscontrol/db/ip.go:266

	var from, to big.Int

	from.SetBytes(fromIP.AsSlice())
	to.SetBytes(toIP.AsSlice())

	// Find the max, this is how we can do "random range",
	// get the "max" as 0 -> to - from and then add back from
	// after.
	tempMax := big.NewInt(0).Sub(&to, &from)

	// A single-address prefix (/32 or /128) has from == to, so tempMax is 0 and
	// rand.Int would panic on a non-positive bound. Return the sole address.
	if tempMax.Sign() <= 0 {
		return fromIP, nil
	}

	out, err := rand.Int(rand.Reader, tempMax)
	if err != nil {
		return netip.Addr{}, fmt.Errorf("generating random IP: %w", err)
	}

	valInRange := big.NewInt(0).Add(&from, out)

	// big.Int.Bytes() strips leading zero bytes, so a value with a zero high
	// byte yields a too-short slice that AddrFromSlice rejects. Pad to the
	// prefix's address width.
	ip, ok := netip.AddrFromSlice(valInRange.FillBytes(make([]byte, len(fromIP.AsSlice()))))
	if !ok {
		return netip.Addr{}, errGeneratedIPBytesInvalid
	}

	if !pfx.Contains(ip) {
		return netip.Addr{}, fmt.Errorf(
			"%w: ip(%s) not in prefix(%s)",
			errGeneratedIPNotInPrefix,
			ip.String(),
			pfx.String(),

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Use sequential allocation strategy to remove the dependency on randomness.
  2. Loosen the container security profile to allow getrandom(2) (Docker's default seccomp already does).
  3. Ensure the host kernel RNG is initialized before headscale starts (check `cat /proc/sys/kernel/random/entropy_avail`).
Defensive patterns

Strategy: fallback

Validate before calling

import "crypto/rand"

func entropyHealthy() error {
    b := make([]byte, 16)
    if _, err := rand.Read(b); err != nil {
        return fmt.Errorf("entropy source unavailable: %w", err)
    }
    return nil
}

Try / catch

// errors.Is on the wrapped crypto/rand error; fall back to sequential
// allocation — never to math/rand for address selection in security-
// relevant deployments, though for pure uniqueness sequential is fine.

Prevention

When it happens

Trigger: rand.Reader read failure: blocked /dev/random in a restricted sandbox, a broken getrandom(2) under a strict seccomp/apparmor profile, or kernel RNG not yet initialized early in boot (rare on modern Linux).

Common situations: Minimal Docker images with restrictive default seccomp denying getrandom; freshly booted VMs; nested virtualization environments; never on correctly configured modern hosts.

Related errors


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