{"record":{"id":"28373ab29eeca3b0","repo":"juanfont/headscale","slug":"generating-registration-id-w","errorCode":null,"errorMessage":"generating registration ID: %w","messagePattern":"generating registration ID: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/auth.go","lineNumber":482,"sourceCode":"\t}\n\n\tlog.Trace().\n\t\tCaller().\n\t\tInterface(\"reg.resp\", resp).\n\t\tInterface(\"reg.req\", req).\n\t\tEmbedObject(node).\n\t\tMsg(\"RegisterResponse\")\n\n\treturn resp, nil\n}\n\nfunc (h *Headscale) handleRegisterInteractive(\n\treq tailcfg.RegisterRequest,\n\tmachineKey key.MachinePublic,\n) (*tailcfg.RegisterResponse, error) {\n\tauthID, err := types.NewAuthID()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"generating registration ID: %w\", err)\n\t}\n\n\tif req.Hostinfo == nil {\n\t\tlog.Warn().\n\t\t\tStr(\"machine.key\", machineKey.ShortString()).\n\t\t\tStr(\"node.key\", req.NodeKey.ShortString()).\n\t\t\tMsg(\"Received registration request with nil hostinfo, generated default hostname\")\n\t} else if req.Hostinfo.Hostname == \"\" {\n\t\tlog.Warn().\n\t\t\tStr(\"machine.key\", machineKey.ShortString()).\n\t\t\tStr(\"node.key\", req.NodeKey.ShortString()).\n\t\t\tMsg(\"Received registration request with empty hostname, generated default\")\n\t}\n\n\tauthRegReq := types.NewRegisterAuthRequest(\n\t\tregistrationDataFromRequest(req, machineKey),\n\t)\n","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/auth.go#L464-L500","documentation":"Wraps a failure of types.NewAuthID() at the start of handleRegisterInteractive (hscontrol/auth.go:486). NewAuthID builds the registration ID as a fixed prefix plus 24 random hex chars via rands.HexString; the only failure mode is the entropy source (crypto/rand) being unavailable to the process. This is a defensive guard that essentially never fires on a healthy system.","triggerScenarios":"Interactive registration (`tailscale login` without an auth key) on a host where crypto/rand cannot be read: getrandom(2) blocked/unavailable, a broken container runtime, or an OS with a misconfigured entropy device.","commonSituations":"Exotic minimal containers (scratch images missing /dev/urandom, odd seccomp profiles blocking getrandom); early-boot registration on entropy-starved embedded systems. On normal Linux/macOS hosts this does not occur because getrandom never blocks after initialization.","solutions":["Verify /dev/urandom exists and is readable inside the container/exec context: ls -l /dev/urandom.","Fix the container spec: do not mask /dev/urandom, allow the getrandom syscall in seccomp, use a standard base image.","Delay registration until after boot entropy initialization on embedded targets.","As a workaround, use pre-auth-key registration, which does not generate an interactive AuthID."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-flight: entropy source available.\nfunc entropyAvailable() error {\n    b := make([]byte, 16)\n    _, err := crand.Read(b)\n    return err\n}","typeGuard":null,"tryCatchPattern":"resp, err := h.handleRegister(req, mk)\nif err != nil && strings.Contains(err.Error(), \"generating registration ID\") {\n    // entropy/getrandom unavailable: fix container spec (/dev/urandom, seccomp), then retry login\n}","preventionTips":["Do not mask /dev/urandom in containers; allow the getrandom syscall in seccomp profiles.","Delay client enrollment until after boot entropy init on embedded hosts.","Use pre-auth keys where interactive registration is impractical."],"tags":["authentication","registration","entropy","containers","unreachable-in-practice"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}