{"record":{"id":"82047c0a133d0e53","repo":"netbirdio/netbird","slug":"peer-and-peer-groups-cannot-be-set-at-the-same-tim","errorCode":null,"errorMessage":"peer and peer_groups cannot be set at the same time","messagePattern":"peer and peer_groups cannot be set at the same time","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"management/server/networks/routers/types/router.go","lineNumber":76,"sourceCode":"\t\tAccountID:  accountID,\n\t\tNetworkID:  networkID,\n\t\tPeer:       peer,\n\t\tPeerGroups: peerGroups,\n\t\tMasquerade: masquerade,\n\t\tMetric:     metric,\n\t\tEnabled:    enabled,\n\t}\n\n\tif err := r.Validate(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r, nil\n}\n\nfunc (n *NetworkRouter) Validate() error {\n\tif n.Peer != \"\" && len(n.PeerGroups) > 0 {\n\t\treturn errors.New(\"peer and peer_groups cannot be set at the same time\")\n\t}\n\n\tif n.Peer == \"\" && len(n.PeerGroups) == 0 {\n\t\treturn errors.New(\"either peer or peer_groups must be provided\")\n\t}\n\n\treturn nil\n}\n\nfunc (n *NetworkRouter) ToAPIResponse() *api.NetworkRouter {\n\treturn &api.NetworkRouter{\n\t\tId:         n.ID,\n\t\tPeer:       &n.Peer,\n\t\tPeerGroups: &n.PeerGroups,\n\t\tMasquerade: n.Masquerade,\n\t\tMetric:     n.Metric,\n\t\tEnabled:    n.Enabled,\n\t}","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/server/networks/routers/types/router.go#L58-L94","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove either the peer field or the peer_groups field from the request payload so exactly one is set","If you need both a specific peer and groups to route that network, create two separate routers for the network"],"exampleFix":"// before\n{\n  \"network_id\": \"nwr-1\",\n  \"peer\": \"p-1\",\n  \"peer_groups\": [\"grp-1\"],\n  \"enabled\": true\n}\n\n// after\n{\n  \"network_id\": \"nwr-1\",\n  \"peer\": \"\",\n  \"peer_groups\": [\"grp-1\"],\n  \"enabled\": true\n}","handlingStrategy":"validation","validationCode":"// Enforce mutual exclusivity before sending the create/update request\nif payload.Peer != \"\" && len(payload.PeerGroups) > 0 {\n    return fmt.Errorf(\"set either peer or peer_groups, not both\")\n}","typeGuard":null,"tryCatchPattern":"resp, err := createRouter(ctx, networkID, payload)\nif err != nil {\n    if strings.Contains(err.Error(), \"peer and peer_groups cannot be set at the same time\") {\n        // clear one side of the payload and retry once\n    }\n    return err\n}","preventionTips":["Model the router payload with one selectable field in UIs: selecting groups must clear peer and vice versa","Omit unused fields (peer or peer_groups) from the JSON instead of sending empty values","When migrating peer -> peer_groups, PATCH with an explicit empty peer and the new groups in one request"],"tags":["management","api","networks","routers","validation"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}