{"record":{"id":"9cf946ea49a0c05f","repo":"netbirdio/netbird","slug":"router-not-part-of-network","errorCode":null,"errorMessage":"router not part of network","messagePattern":"router not part of network","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"management/server/networks/routers/manager.go","lineNumber":151,"sourceCode":"\treturn router, nil\n}\n\nfunc (m *managerImpl) GetRouter(ctx context.Context, accountID, userID, networkID, routerID string) (*types.NetworkRouter, error) {\n\tok, ctx, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)\n\tif err != nil {\n\t\treturn nil, status.NewPermissionValidationError(err)\n\t}\n\tif !ok {\n\t\treturn nil, status.NewPermissionDeniedError()\n\t}\n\n\trouter, err := m.store.GetNetworkRouterByID(ctx, store.LockingStrengthNone, accountID, routerID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get network router: %w\", err)\n\t}\n\n\tif router.NetworkID != networkID {\n\t\treturn nil, errors.New(\"router not part of network\")\n\t}\n\n\treturn router, nil\n}\n\nfunc (m *managerImpl) UpdateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) {\n\tok, ctx, err := m.permissionsManager.ValidateUserPermissions(ctx, router.AccountID, userID, modules.Networks, operations.Update)\n\tif err != nil {\n\t\treturn nil, status.NewPermissionValidationError(err)\n\t}\n\tif !ok {\n\t\treturn nil, status.NewPermissionDeniedError()\n\t}\n\n\tvar network *networkTypes.Network\n\tvar snap *affectedpeers.Snapshot\n\tvar change affectedpeers.Change\n\terr = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error {","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/server/networks/routers/manager.go#L133-L169","documentation":"Returned by managerImpl.GetRouter (management/server/networks/routers/manager.go:151) after the router was successfully fetched by ID from the store: the loaded router exists in the account, but its NetworkID does not equal the networkID argument of the request. It is a referential-integrity guard so a router cannot be read or mutated through the REST path of a network it does not belong to.","triggerScenarios":"Calling GET /api/networks/{networkId}/routers/{routerId} (or the corresponding gRPC/manager call) where routerID belongs to a different network in the same account. Typical after the router was deleted and recreated under another network while a dashboard, CLI or script still holds the old pairing of IDs.","commonSituations":"Stale UI state after a network resource was recreated; scripts that template the network ID but paste a router ID from another environment; renaming/rebuilding networks in IaC pipelines while reusing router IDs.","solutions":["List the routers of the network you are targeting (GET /api/networks/{networkId}/routers) and use the router ID that actually appears there","If the router lives elsewhere, correct the networkId segment of the URL/path to the network the router really belongs to","If the router must serve this network, delete it and create a new one under the correct network (a router's network assignment cannot be moved)"],"exampleFix":"// before: router ctsr-123 belongs to network 'b', not 'a'\nGET /api/networks/a/routers/ctsr-123  // 400 router not part of network\n\n// after: address the router through its actual network\nGET /api/networks/b/routers/ctsr-123","handlingStrategy":"validation","validationCode":"// Before calling GetRouter, confirm the router is in this network\nrouters, err := listNetworkRouters(ctx, accountID, networkID)\nif err != nil { return err }\nfound := false\nfor _, r := range routers {\n    if r.Id == routerID { found = true; break }\n}\nif !found {\n    return fmt.Errorf(\"router %s is not part of network %s; pick one of the listed routers\", routerID, networkID)\n}","typeGuard":null,"tryCatchPattern":"// The error is a plain errors.New (no sentinel); match on message or the API's 400 status\nrouter, err := mgr.GetRouter(ctx, accountID, userID, networkID, routerID)\nif err != nil {\n    if strings.Contains(err.Error(), \"router not part of network\") {\n        // re-enumerate routers of the network and correct the ID\n    }\n    return err\n}","preventionTips":["Always obtain router IDs from a list call on the same network, never from another environment or an older session","After deleting/recreating networks or routers, refresh cached IDs before issuing nested resource calls","In scripts, validate that routerID appears in GET /api/networks/{networkId}/routers before any sub-resource 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"}