netbirdio/netbird · error
either peer or peer_groups must be provided
Error message
either peer or peer_groups must be provided
What it means
Returned by NetworkRouter.Validate (management/server/networks/routers/types/router.go:80): a network router has no destination peer at all. The peer-routing model requires the traffic to be terminated by either one peer or the members of at least one access group, so a router with neither is rejected before persistence.
Source
Thrown at management/server/networks/routers/types/router.go:80
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,
}
}
func (n *NetworkRouter) FromAPIRequest(req *api.NetworkRouterRequest) {
if req.Peer != nil {View on GitHub (pinned to 93e97f4bf1)
Solutions
- Add a routing peer ID in the peer field, or at least one valid group ID in peer_groups
- Create the peer or the group first if it does not exist yet, then create the router
Example fix
// before
{ "network_id": "nwr-1", "enabled": true } // no peer, no peer_groups
// after
{ "network_id": "nwr-1", "peer": "p-1", "enabled": true } Defensive patterns
Strategy: validation
Validate before calling
func hasRoutingPeer(peer string, groups []string) bool {
return peer != "" || len(groups) > 0
}
if !hasRoutingPeer(payload.Peer, payload.PeerGroups) {
return errors.New("provide a routing peer or at least one peer group")
} Try / catch
if err := payload.Validate(); err != nil { // client-side mirror of server Validate()
return err
}
_, err := createRouter(ctx, networkID, payload)
if err != nil && strings.Contains(err.Error(), "either peer or peer_groups") {
// prompt for a peer/group selection instead of retrying blindly
} Prevention
- Make peer/peer_groups required input in forms and scripts; do not support 'create now, attach later'
- Create the routing peer or group first, then the router, in provisioning pipelines
- Assert exactly one of the two fields is non-empty in a shared client-side validator
When it happens
Trigger: POST /api/networks/{networkId}/routers (or update) where peer is empty/omitted and peer_groups is empty or omitted.
Common situations: Creating a router shell first and intending to attach a peer later (not supported); JSON marshalling that drops empty fields; frontend sending an empty array for peer_groups and empty string for peer.
Related errors
- router not part of network
- peer and peer_groups cannot be set at the same time
- posture checks name shouldn't be empty
- posture checks shouldn't be empty
- self deletion is not allowed
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/b61a8d5dcdab77a8.
Report an issue: GitHub.