mirror of
https://github.com/juanfont/headscale.git
synced 2026-05-10 04:34:44 +09:00
Mirror the guard from HandleNodeFromPreAuthKey in HandleNodeFromAuthPath. Both functions log the old user's name in the "different user" branch when an existing NodeStore entry under the same machine key belongs to another user. UserView.Name dereferences the backing User pointer unconditionally, so when the cached node was loaded with a non-nil UserID but a nil User (Preload join missed the row, or upstream code left the snapshot in that shape), the log call panics with a nil-pointer dereference at hscontrol/types/types_view.go:97. The panic is caught by the http2 server's runHandler for the noise control plane, so the process keeps running but every retry produces a new panic — production has observed bursts of ~1.9k panics per hour during a tailscaled reconnect loop. The gRPC/OIDC entry has no equivalent recover and would surface the panic to the caller. Guard both call sites with oldUser.Valid() and fall back to an empty old-user name when the pointer is nil. The "Creating new node for different user" log line still includes the existing node ID, hostname, machine key, and new user, so operator visibility is preserved. Add reproduction tests for both handlers seeding the orphan shape directly into NodeStore via PutNodeInStoreForTest. Co-Authored-By: Kristoffer Dalby <kristoffer@dalby.cc>