netbirdio/netbird · error
add elements to set %s: %w
Error message
add elements to set %s: %w
What it means
UpdateSet converts the prefixes to set elements and adds them with SetAddElements, which writes NFT_MSG_NEWSETELEM to the kernel immediately. Failures include ENOENT (the set vanished between GetSetByName and the add), netlink message-size limits with very large element batches (the package documents that about 1638 prefixes start to fail and caps usage at maxPrefixesSet=1500), and permission errors.
Source
Thrown at client/firewall/nftables/router_linux.go:1862
delete(r.rules, ruleKey+snatSuffix)
if err := r.ipFwdState.ReleaseForwarding(r.af.tableFamily == nftables.TableFamilyIPv6); err != nil {
log.Errorf("%v", err)
}
}
return nberrors.FormatErrorOrNil(merr)
}
func (r *router) UpdateSet(set firewall.Set, prefixes []netip.Prefix) error {
nfset, err := r.conn.GetSetByName(r.workTable, set.HashedName())
if err != nil {
return fmt.Errorf("get set %s: %w", set.HashedName(), err)
}
elements := r.convertPrefixesToSet(prefixes)
if err := r.conn.SetAddElements(nfset, elements); err != nil {
return fmt.Errorf("add elements to set %s: %w", set.HashedName(), err)
}
if err := r.conn.Flush(); err != nil {
return fmt.Errorf(flushError, err)
}
log.Debugf("updated set %s with prefixes %v", set.HashedName(), prefixes)
return nil
}
// AddInboundDNAT adds an inbound DNAT rule redirecting traffic from NetBird peers to local services.
func (r *router) AddInboundDNAT(localAddr netip.Addr, protocol firewall.Protocol, originalPort, translatedPort uint16) error {
ruleID := fmt.Sprintf("inbound-dnat-%s-%s-%d-%d", localAddr.String(), protocol, originalPort, translatedPort)
if _, exists := r.rules[ruleID]; exists {
return nil
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Chunk element additions below the netlink limit (the codebase treats 1500 as the safe bound).
- Retry after confirming the set still exists with 'sudo nft list set <table> <name>'.
- Prefer adding only new elements (diff) over re-adding the full prefix list each update.
- Verify CAP_NET_ADMIN when the error is not size-related.
Example fix
// before
elements := r.convertPrefixesToSet(prefixes)
if err := r.conn.SetAddElements(nfset, elements); err != nil {
return fmt.Errorf("add elements to set %s: %w", set.HashedName(), err)
}
// after: chunk to stay under netlink message limits
const chunkSize = 512
elements := r.convertPrefixesToSet(prefixes)
for i := 0; i < len(elements); i += chunkSize {
end := min(i+chunkSize, len(elements))
if err := r.conn.SetAddElements(nfset, elements[i:end]); err != nil {
return fmt.Errorf("add elements to set %s (chunk at %d): %w", set.HashedName(), i, err)
}
} Defensive patterns
Strategy: validation
Validate before calling
// Stay under the netlink element limit before adding
const maxPrefixesSet = 1500 // ~1638 starts to fail in practice
func prefixBatchSafe(n int) error {
if n > maxPrefixesSet {
return fmt.Errorf("%d prefixes exceeds the safe netlink batch limit %d; split the update", n, maxPrefixesSet)
}
return nil
} Try / catch
elements := r.convertPrefixesToSet(prefixes)
if err := r.conn.SetAddElements(nfset, elements); err != nil {
if errors.Is(err, unix.EMSGSIZE) || errors.Is(err, unix.ENOMEM) {
// batch too large: caller should chunk and retry
return fmt.Errorf("add elements to set %s: batch of %d too large: %w", set.HashedName(), len(elements), err)
}
return fmt.Errorf("add elements to set %s: %w", set.HashedName(), err)
} Prevention
- Chunk prefix updates (for example 512 elements per call) to stay clear of netlink message limits.
- Diff prefix lists so unchanged elements are not re-added every update.
- Track set sizes in monitoring to catch growth toward the ~1500-element danger zone.
When it happens
Trigger: One UpdateSet call carrying hundreds or thousands of prefixes; the set deleted concurrently mid-update; unprivileged netlink access.
Common situations: Large network routes (big CIDR lists) pushed in a single update; races with external nft flush; hosts with small netlink buffers.
Related errors
- error adding prefixes (%d) to set %s: %w
- get set %s: %w
- decrement set counter: %w
- error adding set %s: %w
- flush error: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/01c31708a77c9662.
Report an issue: GitHub.