juanfont/headscale · error

updating policy manager users: %w

Error message

updating policy manager users: %w

What it means

After a node was fully registered and the auth-cache entry finished (regEntry.FinishAuth already called), rebuilding the policy manager's user set failed. The node registration itself succeeded, but the function returns the error alongside change.NodeAdded — policy evaluation state may not include the new user.

Source

Thrown at hscontrol/state/state.go:2346

		finalNode, err = s.createNewNodeFromAuth(
			logger, user, regData, hostname, hostinfo,
			expiry, registrationMethod, types.NodeView{},
		)
		if err != nil {
			return types.NodeView{}, change.Change{}, err
		}
	}

	// Signal to waiting clients
	regEntry.FinishAuth(types.AuthVerdict{Node: finalNode})

	// Remove from registration cache
	s.authCache.Remove(authID)

	// Update policy managers
	usersChange, err := s.updatePolicyManagerUsers()
	if err != nil {
		return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("updating policy manager users: %w", err)
	}

	nodesChange, err := s.updatePolicyManagerNodes()
	if err != nil {
		return finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf("updating policy manager nodes: %w", err)
	}

	policyChanged := !usersChange.IsEmpty() || !nodesChange.IsEmpty()

	// nodeExistsForSameUser is true only for a same-user relogin; a tag->user
	// conversion is excluded, as it changes the peer's User — a structural
	// change peers must see in full, not a key-rotation patch.
	return finalNode, reauthChange(finalNode, nodeExistsForSameUser, policyChanged), nil
}

// createNewNodeFromAuth creates a new node during auth callback.
// This is used for both new registrations and when a machine already has a node
// for a different user.

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Validate and fix the policy file: `headscale policy check` / reload via API
  2. Retry the registration — once policy parses cleanly the user set updates on the next pass
  3. Check headscale logs for the underlying policy compilation error chained in %w
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate policy parses before enabling OIDC-driven registrations:
if err := policy.Parse(currentPolicySrc); err != nil {
    return fmt.Errorf("policy invalid; fix before users register: %w", err)
}

Try / catch

if err != nil && strings.Contains(err.Error(), "updating policy manager users") {
    // Node registered successfully; policy view stale. Fix policy then force a policy update.
    log.Error().Err(err).Msg("registration succeeded but policy users stale")
}

Prevention

When it happens

Trigger: updatePolicyManagerUsers() errors while applying the user list to the policy engine: malformed policy source re-parsed at this point, policy compiler error, or an internal v2 policy manager update failure during the auth callback.

Common situations: Policy file edited to an invalid HuJSON right as a user finished OIDC login; policy referencing a user that no longer resolves during manager rebuild.

Related errors


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