{"record":{"id":"b00acfa420dc2713","repo":"juanfont/headscale","slug":"updating-policy-manager-users-w","errorCode":null,"errorMessage":"updating policy manager users: %w","messagePattern":"updating policy manager users: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/state/state.go","lineNumber":2346,"sourceCode":"\t\tfinalNode, err = s.createNewNodeFromAuth(\n\t\t\tlogger, user, regData, hostname, hostinfo,\n\t\t\texpiry, registrationMethod, types.NodeView{},\n\t\t)\n\t\tif err != nil {\n\t\t\treturn types.NodeView{}, change.Change{}, err\n\t\t}\n\t}\n\n\t// Signal to waiting clients\n\tregEntry.FinishAuth(types.AuthVerdict{Node: finalNode})\n\n\t// Remove from registration cache\n\ts.authCache.Remove(authID)\n\n\t// Update policy managers\n\tusersChange, err := s.updatePolicyManagerUsers()\n\tif err != nil {\n\t\treturn finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf(\"updating policy manager users: %w\", err)\n\t}\n\n\tnodesChange, err := s.updatePolicyManagerNodes()\n\tif err != nil {\n\t\treturn finalNode, change.NodeAdded(finalNode.ID()), fmt.Errorf(\"updating policy manager nodes: %w\", err)\n\t}\n\n\tpolicyChanged := !usersChange.IsEmpty() || !nodesChange.IsEmpty()\n\n\t// nodeExistsForSameUser is true only for a same-user relogin; a tag->user\n\t// conversion is excluded, as it changes the peer's User — a structural\n\t// change peers must see in full, not a key-rotation patch.\n\treturn finalNode, reauthChange(finalNode, nodeExistsForSameUser, policyChanged), nil\n}\n\n// createNewNodeFromAuth creates a new node during auth callback.\n// This is used for both new registrations and when a machine already has a node\n// for a different user.","sourceCodeStart":2328,"sourceCodeEnd":2364,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/state/state.go#L2328-L2364","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Validate policy parses before enabling OIDC-driven registrations:\nif err := policy.Parse(currentPolicySrc); err != nil {\n    return fmt.Errorf(\"policy invalid; fix before users register: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"updating policy manager users\") {\n    // Node registered successfully; policy view stale. Fix policy then force a policy update.\n    log.Error().Err(err).Msg(\"registration succeeded but policy users stale\")\n}","preventionTips":["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"],"tags":["policy","users","oidc","registration","go"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}