netbirdio/netbird · error
router not part of network
Error message
router not part of network
What it means
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.
Source
Thrown at management/server/networks/routers/manager.go:151
return router, nil
}
func (m *managerImpl) GetRouter(ctx context.Context, accountID, userID, networkID, routerID string) (*types.NetworkRouter, error) {
ok, ctx, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
if err != nil {
return nil, status.NewPermissionValidationError(err)
}
if !ok {
return nil, status.NewPermissionDeniedError()
}
router, err := m.store.GetNetworkRouterByID(ctx, store.LockingStrengthNone, accountID, routerID)
if err != nil {
return nil, fmt.Errorf("failed to get network router: %w", err)
}
if router.NetworkID != networkID {
return nil, errors.New("router not part of network")
}
return router, nil
}
func (m *managerImpl) UpdateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) {
ok, ctx, err := m.permissionsManager.ValidateUserPermissions(ctx, router.AccountID, userID, modules.Networks, operations.Update)
if err != nil {
return nil, status.NewPermissionValidationError(err)
}
if !ok {
return nil, status.NewPermissionDeniedError()
}
var network *networkTypes.Network
var snap *affectedpeers.Snapshot
var change affectedpeers.Change
err = m.store.ExecuteInTransaction(ctx, func(transaction store.Store) error {View on GitHub (pinned to 93e97f4bf1)
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)
Example fix
// before: router ctsr-123 belongs to network 'b', not 'a' GET /api/networks/a/routers/ctsr-123 // 400 router not part of network // after: address the router through its actual network GET /api/networks/b/routers/ctsr-123
Defensive patterns
Strategy: validation
Validate before calling
// Before calling GetRouter, confirm the router is in this network
routers, err := listNetworkRouters(ctx, accountID, networkID)
if err != nil { return err }
found := false
for _, r := range routers {
if r.Id == routerID { found = true; break }
}
if !found {
return fmt.Errorf("router %s is not part of network %s; pick one of the listed routers", routerID, networkID)
} Try / catch
// The error is a plain errors.New (no sentinel); match on message or the API's 400 status
router, err := mgr.GetRouter(ctx, accountID, userID, networkID, routerID)
if err != nil {
if strings.Contains(err.Error(), "router not part of network") {
// re-enumerate routers of the network and correct the ID
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- peer and peer_groups cannot be set at the same time
- either peer or peer_groups must be provided
- 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/9cf946ea49a0c05f.
Report an issue: GitHub.