juanfont/headscale · error

setting node expiry in database

Error message

setting node expiry in database: %w

What it means

Error "setting node expiry in database: %w" thrown in juanfont/headscale.

Solutions

  1. 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.

Example fix

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.

When it happens

Trigger: Thrown at hscontrol/state/state.go:918 when the library encounters an invalid state.

Common situations: Writing the node expiry to the database failed. Check database connectivity and that the node still exists.


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

Appendix: source

Thrown at hscontrol/state/state.go:918

// If expiry is nil, the node's expiry is disabled (node will never expire).
func (s *State) SetNodeExpiry(nodeID types.NodeID, expiry *time.Time) (types.NodeView, change.Change, error) {
	// Update [NodeStore] before database to ensure consistency. The [NodeStore] update
	// is blocking and will be the source of truth for the batcher. The database update
	// must make the exact same change. If the database update fails, the [NodeStore]
	// change will remain, but since we return an error, no change notification will be
	// sent to the batcher, preventing inconsistent state propagation.
	n, ok := s.nodeStore.UpdateNode(nodeID, func(node *types.Node) {
		node.Expiry = expiry
	})

	if !ok {
		return types.NodeView{}, change.Change{}, fmt.Errorf("%w: %d", ErrNodeNotInNodeStore, nodeID)
	}

	// Persist expiry change to database directly since persistNodeToDB omits expiry.
	err := s.db.NodeSetExpiry(nodeID, expiry)
	if err != nil {
		return types.NodeView{}, change.Change{}, fmt.Errorf("setting node expiry in database: %w", err)
	}

	// Update policy manager and generate change notification.
	c, err := s.updatePolicyManagerNodes()
	if err != nil {
		return n, change.Change{}, fmt.Errorf("updating policy manager after setting expiry: %w", err)
	}

	if c.IsEmpty() {
		c = change.NodeAdded(n.ID())
	}

	return n, c, nil
}

// SetNodeTags assigns tags to a node, making it a "tagged node".
// Once a node is tagged, it cannot be un-tagged (only tags can be changed).
// Setting tags clears UserID since tagged nodes are owned by their tags.

View on GitHub (pinned to 565fd254d0)