netbirdio/netbird · error

peer and peer_groups cannot be set at the same time

Error message

peer and peer_groups cannot be set at the same time

What it means

Returned by NetworkRouter.Validate (management/server/networks/routers/types/router.go:76): a network router must select exactly one routing peer source, either a single peer or a list of peer groups, never both. Validation runs inside NewNetworkRouter, so it fires on router creation and update before anything is persisted.

Source

Thrown at management/server/networks/routers/types/router.go:76

		AccountID:  accountID,
		NetworkID:  networkID,
		Peer:       peer,
		PeerGroups: peerGroups,
		Masquerade: masquerade,
		Metric:     metric,
		Enabled:    enabled,
	}

	if err := r.Validate(); err != nil {
		return nil, err
	}

	return r, nil
}

func (n *NetworkRouter) Validate() error {
	if n.Peer != "" && len(n.PeerGroups) > 0 {
		return errors.New("peer and peer_groups cannot be set at the same time")
	}

	if n.Peer == "" && len(n.PeerGroups) == 0 {
		return errors.New("either peer or peer_groups must be provided")
	}

	return nil
}

func (n *NetworkRouter) ToAPIResponse() *api.NetworkRouter {
	return &api.NetworkRouter{
		Id:         n.ID,
		Peer:       &n.Peer,
		PeerGroups: &n.PeerGroups,
		Masquerade: n.Masquerade,
		Metric:     n.Metric,
		Enabled:    n.Enabled,
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Remove either the peer field or the peer_groups field from the request payload so exactly one is set
  2. If you need both a specific peer and groups to route that network, create two separate routers for the network

Example fix

// before
{
  "network_id": "nwr-1",
  "peer": "p-1",
  "peer_groups": ["grp-1"],
  "enabled": true
}

// after
{
  "network_id": "nwr-1",
  "peer": "",
  "peer_groups": ["grp-1"],
  "enabled": true
}
Defensive patterns

Strategy: validation

Validate before calling

// Enforce mutual exclusivity before sending the create/update request
if payload.Peer != "" && len(payload.PeerGroups) > 0 {
    return fmt.Errorf("set either peer or peer_groups, not both")
}

Try / catch

resp, err := createRouter(ctx, networkID, payload)
if err != nil {
    if strings.Contains(err.Error(), "peer and peer_groups cannot be set at the same time") {
        // clear one side of the payload and retry once
    }
    return err
}

Prevention

When it happens

Trigger: POST /api/networks/{networkId}/routers or PATCH on a router whose payload contains a non-empty peer field AND a non-empty peer_groups array at the same time.

Common situations: Migrating a router from a single peer to groups and leaving the old peer field in the payload; UI forms that keep a previously selected peer visible when the operator switches to group selection; API clients sending zero-valued-but-serialized fields that deserialize to a non-empty value.

Related errors


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