juanfont/headscale · error

setting node expiry in database: %w

Error message

setting node expiry in database: %w

What it means

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

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)

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.