juanfont/headscale · error

finding user: %w

Error message

finding user: %w

What it means

During the auth callback (OIDC/interactive login), looking up the user selected for the new registration failed: s.db.GetUserByID(userID) errored. The registration cache entry was already fetched successfully, so this is purely a user-table read failure or a missing user record.

Source

Thrown at hscontrol/state/state.go:2220

}

// HandleNodeFromAuthPath handles node registration through authentication flow (like OIDC).
func (s *State) HandleNodeFromAuthPath(
	authID types.AuthID,
	userID types.UserID,
	expiry *time.Time,
	registrationMethod string,
) (types.NodeView, change.Change, error) {
	// Get the registration entry from cache
	regEntry, ok := s.GetAuthCacheEntry(authID)
	if !ok {
		return types.NodeView{}, change.Change{}, hsdb.ErrNodeNotFoundRegistrationCache
	}

	// Get the user
	user, err := s.db.GetUserByID(userID)
	if err != nil {
		return types.NodeView{}, change.Change{}, fmt.Errorf("finding user: %w", err)
	}

	regData := regEntry.RegistrationData()

	// Hostname was already validated/normalised at producer time. Build
	// the initial Hostinfo from the cached client-supplied Hostinfo (or
	// an empty stub if the client did not send one).
	hostname := regData.Hostname

	hostinfo := &tailcfg.Hostinfo{}
	if regData.Hostinfo != nil {
		hostinfo = regData.Hostinfo.Clone()
	}

	hostinfo.Hostname = hostname

	// Lookup existing nodes
	machineKey := regData.MachineKey

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Confirm the user still exists: `headscale users list`
  2. If deleted, restart the login flow for a valid user
  3. For DB read errors, restore connectivity and retry — the client re-initiates registration cleanly
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the user exists before completing the callback:
if _, err := db.GetUserByID(userID); err != nil {
    http.Redirect(w, r, "/register?error=user_missing", http.StatusTemporaryRedirect)
    return
}

Try / catch

node, ch, err := s.CompleteRegistration(authID, userID, ...)
if err != nil && strings.Contains(err.Error(), "finding user") {
    // user deleted mid-login; restart flow with a fresh auth URL
    s.authCache.Remove(authID)
    renderError(w, "user no longer exists; start a new login")
    return
}

Prevention

When it happens

Trigger: CompleteRegisterWithAuthKey/auth callback invoked with a userID that does not exist (user deleted between login start and callback), or the DB read fails outright — connection dropped, table locked, Postgres failover.

Common situations: Admin deletes a user while that user's OIDC login is in flight; long-lived browser login page resumed after the user was removed; transient DB outage at callback time.

Related errors


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