{"record":{"id":"85c3597796072cce","repo":"juanfont/headscale","slug":"updating-policy-manager-nodes-w","errorCode":null,"errorMessage":"updating policy manager nodes: %w","messagePattern":"updating policy manager nodes: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/state/state.go","lineNumber":2351,"sourceCode":"\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.\nfunc (s *State) createNewNodeFromAuth(\n\tlogger zerolog.Logger,\n\tuser *types.User,\n\tregData *types.RegistrationData,\n\thostname string,","sourceCodeStart":2333,"sourceCodeEnd":2369,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/state/state.go#L2333-L2369","documentation":"Same auth-callback tail as the users update, but for the node set: updatePolicyManagerNodes() failed after the node was registered, the cache entry finished, and the users update succeeded. The node exists in NodeStore and DB; only the policy manager's view of nodes is stale until the next successful policy update.","triggerScenarios":"updatePolicyManagerNodes() returning an error during the registration callback — policy engine rejecting the node list, or a v2 policy manager internal error while filtering peers.","commonSituations":"Corrupted or edge-case policy (e.g. autogroup referencing missing entities) that only fails once real nodes are fed in; policy hot-reload racing the callback.","solutions":["Inspect the wrapped error for the policy-engine cause in server logs","Fix/reload the policy, then trigger any policy update so the node set is rebuilt","Verify with `headscale nodes list` and a peer status check that connectivity converges afterwards"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"updating policy manager nodes\") {\n    // Registration persisted; node policy view stale until next policy update\n    log.Error().Err(err).Msg(\"node registered; policy nodes refresh pending\")\n    // self-heal: schedule updatePolicyManagerNodes()\n}","preventionTips":["After any policy manager error, run a policy no-op update to rebuild node sets","Keep policy syntax valid — most manager update failures trace to policy source","Test peer connectivity after registration completes to detect stale policy views"],"tags":["policy","nodes","registration","go"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}