{"record":{"id":"567efabbfffad175","repo":"juanfont/headscale","slug":"getting-random-ip-w","errorCode":null,"errorMessage":"getting random IP: %w","messagePattern":"getting random IP: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/db/ip.go","lineNumber":197,"sourceCode":"\t*prev = *ret\n\n\treturn ret, nil\n}\n\nfunc (i *IPAllocator) next(prev netip.Addr, prefix *netip.Prefix) (*netip.Addr, error) {\n\tvar (\n\t\terr error\n\t\tip  netip.Addr\n\t)\n\n\tswitch i.strategy {\n\tcase types.IPAllocationStrategySequential:\n\t\t// Get the first IP in our prefix\n\t\tip = prev.Next()\n\tcase types.IPAllocationStrategyRandom:\n\t\tip, err = randomNext(*prefix)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting random IP: %w\", err)\n\t\t}\n\t}\n\n\t// TODO(kradalby): maybe this can be done less often.\n\tset, err := i.usedIPs.IPSet()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Walk forward from the starting address until a free, non-reserved\n\t// address inside the prefix is found. The random strategy only picks the\n\t// starting point at random and then scans deterministically: this keeps\n\t// the loop finite, so an exhausted prefix returns ErrCouldNotAllocateIP\n\t// instead of re-drawing in-prefix addresses forever under i.mu.\n\tstart := ip\n\tfor {\n\t\tif prefix.Contains(ip) && !set.Contains(ip) && !isTailscaleReservedIP(ip) {\n\t\t\ti.usedIPs.Add(ip)","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/db/ip.go#L179-L215","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Switch ip_allocation_strategy to sequential — deterministic and avoids the entropy path entirely.","Fix the environment's entropy: ensure /dev/urandom is available and not blocked by the container runtime/seccomp.","Check dmesg/kernel logs for RNG initialization failures on the host."],"exampleFix":"# before (config.yaml)\nip_allocation_strategy: random\n\n# after\nip_allocation_strategy: sequential","handlingStrategy":"fallback","validationCode":"// Environment pre-check for the random strategy:\n// cat /proc/sys/kernel/random/entropy_avail  # expect > 128\n// Or in Go: read 16 bytes from crypto/rand and time it.","typeGuard":null,"tryCatchPattern":"// Catch and fall back to sequential allocation for that request:\n//   ip, err := alloc.Next()\n//   if err != nil && strings.Contains(err.Error(), \"getting random IP\") {\n//       ip, err = sequentialAlloc.Next() // or reconfigure strategy and retry\n//   }","preventionTips":["Prefer sequential strategy in constrained/sandboxed environments.","Verify /dev/urandom availability in container images."],"tags":["ip-allocation","random","entropy","crypto-rand"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}