{"record":{"id":"08ff7e2fb2349d6d","repo":"juanfont/headscale","slug":"setting-node-expiry-in-database-w","errorCode":null,"errorMessage":"setting node expiry in database: %w","messagePattern":"setting node expiry in database: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"hscontrol/state/state.go","lineNumber":918,"sourceCode":"// If expiry is nil, the node's expiry is disabled (node will never expire).\nfunc (s *State) SetNodeExpiry(nodeID types.NodeID, expiry *time.Time) (types.NodeView, change.Change, error) {\n\t// Update [NodeStore] before database to ensure consistency. The [NodeStore] update\n\t// is blocking and will be the source of truth for the batcher. The database update\n\t// must make the exact same change. If the database update fails, the [NodeStore]\n\t// change will remain, but since we return an error, no change notification will be\n\t// sent to the batcher, preventing inconsistent state propagation.\n\tn, ok := s.nodeStore.UpdateNode(nodeID, func(node *types.Node) {\n\t\tnode.Expiry = expiry\n\t})\n\n\tif !ok {\n\t\treturn types.NodeView{}, change.Change{}, fmt.Errorf(\"%w: %d\", ErrNodeNotInNodeStore, nodeID)\n\t}\n\n\t// Persist expiry change to database directly since persistNodeToDB omits expiry.\n\terr := s.db.NodeSetExpiry(nodeID, expiry)\n\tif err != nil {\n\t\treturn types.NodeView{}, change.Change{}, fmt.Errorf(\"setting node expiry in database: %w\", err)\n\t}\n\n\t// Update policy manager and generate change notification.\n\tc, err := s.updatePolicyManagerNodes()\n\tif err != nil {\n\t\treturn n, change.Change{}, fmt.Errorf(\"updating policy manager after setting expiry: %w\", err)\n\t}\n\n\tif c.IsEmpty() {\n\t\tc = change.NodeAdded(n.ID())\n\t}\n\n\treturn n, c, nil\n}\n\n// SetNodeTags assigns tags to a node, making it a \"tagged node\".\n// Once a node is tagged, it cannot be un-tagged (only tags can be changed).\n// Setting tags clears UserID since tagged nodes are owned by their tags.","sourceCodeStart":900,"sourceCodeEnd":936,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/state/state.go#L900-L936","documentation":"Error \"setting node expiry in database: %w\" thrown in juanfont/headscale.","triggerScenarios":"Thrown at hscontrol/state/state.go:918 when the library encounters an invalid state.","commonSituations":"Writing the node expiry to the database failed. Check database connectivity and that the node still exists.","solutions":["Inspect the wrapped error for the underlying cause and correct the failing condition (setting node expiry in database); retry the operation after fixing the input, configuration, or environment."],"exampleFix":"Inspect the wrapped error for the underlying cause and correct the failing condition (setting node expiry in database); retry the operation after fixing the input, configuration, or environment.","handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}