netbirdio/netbird · error

get set %s: %w

Error message

get set %s: %w

What it means

UpdateSet fetches the existing nftables named set by its hashed name with GetSetByName before adding elements. The error wraps a failed NFT_MSG_GETSET lookup: most commonly ENOENT because the set was never created (sets are created lazily by the refcounter when the first referencing rule is added) or was flushed away, with netlink or permission failures as the rarer cause.

Source

Thrown at client/firewall/nftables/router_linux.go:1857

	// Release the refcount only once the rules are gone from the kernel. On
	// failure (including the refreshRulesMap error above) the rules and their
	// map entries remain, keeping forwarding on until a retry removes them.
	if merr == nil {
		delete(r.rules, ruleKey+dnatSuffix)
		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 {

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Confirm the set exists: 'sudo nft list sets' and look for the hashed set name.
  2. Ensure the rules referencing the set are added first so createIpSet runs before UpdateSet.
  3. Recreate state by re-applying the route/firewall configuration (network-map refresh or agent restart).
  4. For non-ENOENT failures, check root/CAP_NET_ADMIN.

Example fix

// before
nfset, err := r.conn.GetSetByName(r.workTable, set.HashedName())
if err != nil {
    return fmt.Errorf("get set %s: %w", set.HashedName(), err)
}

// after: lazily (re)create the set when it disappeared
nfset, err := r.conn.GetSetByName(r.workTable, set.HashedName())
if errors.Is(err, unix.ENOENT) {
    nfset, err = r.createIpSet(set.HashedName(), setInput{set: set, prefixes: prefixes})
    if err != nil {
        return fmt.Errorf("recreate set %s: %w", set.HashedName(), err)
    }
} else if err != nil {
    return fmt.Errorf("get set %s: %w", set.HashedName(), err)
}
Defensive patterns

Strategy: fallback

Validate before calling

// Verify the set exists before updating it
func setExists(conn *nftables.Conn, table *nftables.Table, hashedName string) bool {
    _, err := conn.GetSetByName(table, hashedName)
    return err == nil
}

Try / catch

nfset, err := r.conn.GetSetByName(r.workTable, set.HashedName())
if err != nil {
    if !errors.Is(err, unix.ENOENT) {
        return fmt.Errorf("get set %s: %w", set.HashedName(), err)
    }
    // set vanished: fall back to recreating it, then continue the update
    nfset, err = r.createIpSet(set.HashedName(), setInput{set: set})
    if err != nil {
        return fmt.Errorf("recreate set %s: %w", set.HashedName(), err)
    }
}

Prevention

When it happens

Trigger: UpdateSet called for a set whose createIpSet never ran or failed earlier; an external flush removed the netbird table's sets; GETSET blocked by missing CAP_NET_ADMIN.

Common situations: Route or network update events arriving before the rules that create the set; recovery after an external ruleset wipe; ordering regressions in code that updates sets independently of rule lifecycle.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/1097fc1c510060c2. Report an issue: GitHub.