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
- Validate and fix the policy file: `headscale policy check` / reload via API
- Retry the registration — once policy parses cleanly the user set updates on the next pass
- 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
- Validate policy on every edit (headscale policy check / CI on policy file changes)
- Remember the node IS registered despite this error — don't double-register on retry
- Trigger a policy reload after fixing to rebuild the manager's user set
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.