juanfont/headscale · error

nodeAttrs ipPool requires the IP allocator (https://github.c

Error message

nodeAttrs ipPool requires the IP allocator (https://github.com/juanfont/headscale/issues/2912)

What it means

Returned unconditionally at hscontrol/policy/v2/types.go:2718-2719 whenever a nodeAttrs entry has a non-empty ipPool list. The ipPool feature depends on an IP allocator that headscale has not implemented (tracked at https://github.com/juanfont/headscale/issues/2912), so any ipPool key is rejected at policy load regardless of whether the prefixes themselves are valid.

Source

Thrown at hscontrol/policy/v2/types.go:92

// Grant validation errors.
var (
	ErrGrantMissingIPOrApp             = errors.New("ip and app can not both be empty")
	ErrGrantViaNotATag                 = errors.New("via can only be a tag")
	ErrProtocolPortInvalidFormat       = errors.New("expected only one colon in Internet protocol and port type")
	ErrCapNameInvalidForm              = errors.New("capability name must have the form {domain}/{path}")
	ErrCapNameTailscaleDomain          = errors.New("capability name must not be in the tailscale.com domain")
	ErrGrantAutogroupSelfInvalidSource = errors.New("autogroup:self can only be used with users, groups, or supported autogroups")
	ErrGrantAppWithAutogroupInternet   = errors.New("cannot use app grants with autogroup:internet")
	ErrGrantDefaultRouteCIDR           = errors.New("to allow all IP addresses, use \"*\" or \"autogroup:internet\"")
)

// NodeAttrs validation errors.
var (
	ErrNodeAttrsIPPoolReserved      = errors.New("nodeAttrs ipPool must not overlap reserved Tailscale ranges")
	ErrNodeAttrsIPPoolOutOfRange    = errors.New("nodeAttrs ipPool must be within 100.64.0.0/10")
	ErrNodeAttrsAutogroupNotAllowed = errors.New("nodeAttrs target does not support this autogroup")
	ErrNodeAttrUnsupported          = errors.New("nodeAttrs uses a feature headscale does not yet support")
	ErrNodeAttrIPPoolUnsupported    = errors.New("nodeAttrs ipPool requires the IP allocator (https://github.com/juanfont/headscale/issues/2912)")
	ErrNodeAttrTargetUnsupported    = errors.New("nodeAttrs target alias type is not supported")
)

// nodeAttrUnsupportedCaps lists caps that headscale parses but cannot act on
// today. Each entry maps to the tracking issue an operator can follow. The
// caps are accepted by Tailscale SaaS, but delivering them via headscale
// without the matching server-side machinery would be misleading — nodes
// would advertise a feature that does not work. Reject at policy load and
// point operators at the issue.
var nodeAttrUnsupportedCaps = map[tailcfg.NodeCapability]string{
	tailcfg.NodeAttrFunnel: "https://github.com/juanfont/headscale/issues/2527",
}

// Policy validation errors.
var (
	ErrInvalidUsername             = errors.New("username must contain @")
	ErrUserNotFound                = errors.New("user not found")
	ErrMultipleUsersFound          = errors.New("multiple users found")

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Delete the ipPool key from every nodeAttrs block
  2. Track issue #2912 for IP allocator support
  3. If you need deterministic node addressing, rely on existing prefix allocation config outside policy ipPool

Example fix

// before
{"nodeAttrs": [{"target": ["autogroup:member"], "ipPool": ["100.80.0.0/16"]}]}
// after
{"nodeAttrs": [{"target": ["autogroup:member"]}]}
Defensive patterns

Strategy: validation

Validate before calling

for _, na := range policy.NodeAttrs {
    if len(na.IPPool) > 0 {
        return errors.New("nodeAttrs ipPool is not supported by headscale yet")
    }
}

Type guard

null

Try / catch

if errors.Is(err, policy.ErrNodeAttrIPPoolUnsupported) {
    // remove ipPool blocks; feature pending issue #2912
}

Prevention

When it happens

Trigger: Any policy with {"nodeAttrs": [{"ipPool": ["100.100.1.0/24"]}]} (any CIDR, even a valid in-range one) fails validation; the same entry may additionally produce range errors, but the unsupported-feature error fires first because the feature does not exist yet.

Common situations: Copying a Tailscale SaaS policy that provisions per-node IP pools; testing whether ipPool silently no-ops and discovering it hard-fails; upgrading headscale and having a previously unimplemented-but-ignored key now rejected.

Related errors


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