netbirdio/netbird · error
resource not part of network
Error message
resource not part of network
What it means
Returned by managerImpl.GetResource: the resource was fetched by ID successfully, but its resource.NetworkID does not equal the networkID argument of the request. The API route is scoped to /networks/{networkId}/resources/{resourceId}, so this fires when the two IDs belong to different networks. It surfaces as a client error, not a store error.
Source
Thrown at management/server/networks/resources/manager.go:200
return eventsToStore, snap, nil
}
func (m *managerImpl) GetResource(ctx context.Context, accountID, userID, networkID, resourceID string) (*types.NetworkResource, 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()
}
resource, err := m.store.GetNetworkResourceByID(ctx, store.LockingStrengthNone, accountID, resourceID)
if err != nil {
return nil, fmt.Errorf("failed to get network resource: %w", err)
}
if resource.NetworkID != networkID {
return nil, errors.New("resource not part of network")
}
return resource, nil
}
func (m *managerImpl) UpdateResource(ctx context.Context, userID string, resource *types.NetworkResource) (*types.NetworkResource, error) {
ok, ctx, err := m.permissionsManager.ValidateUserPermissions(ctx, resource.AccountID, userID, modules.Networks, operations.Update)
if err != nil {
return nil, status.NewPermissionValidationError(err)
}
if !ok {
return nil, status.NewPermissionDeniedError()
}
resourceType, domain, prefix, err := types.GetResourceType(resource.Address)
if err != nil {
return nil, fmt.Errorf("failed to get resource type: %w", err)
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Call the list-resources endpoint of the specific network and use the IDs it returns, so resource and network always match.
- Refresh cached IDs after networks or resources are recreated.
- Double-check you are using a network resource ID, not a network router or route ID, in the path.
Example fix
// before
GET /api/networks/{networkA}/resources/{resB}
// after
GET /api/networks/{networkB}/resources/{resB} // resB belongs to networkB Defensive patterns
Strategy: validation
Validate before calling
// before GetResource: confirm the resource is listed under this network
list, err := m.GetNetworkResources(ctx, accountID, userID, networkID) // or the store list call
for _, r := range list {
if r.Id == resourceID { /* safe to call GetResource */ }
} Try / catch
res, err := m.GetResource(ctx, accountID, userID, networkID, resourceID)
if err != nil {
if err.Error() == "resource not part of network" {
// treat as not-found for this network: refresh IDs, do not blind-retry
}
return nil, err
} Prevention
- Always obtain resource IDs by listing under the specific network, never from a global cache.
- Invalidate cached IDs whenever networks or resources are recreated.
- Treat this error as 404-equivalent in clients: refresh and re-navigate, never retry the same pair.
When it happens
Trigger: GET /api/networks/{networkA-id}/resources/{resource-of-networkB-id}; a stale resourceId captured before the network or resource was recreated; scripts iterating resources across networks while reusing a single networkID.
Common situations: A UI holding a cached resource ID after the network was recreated; copy-pasting IDs between environments; confusing the network-router resource ID with the network resource ID (similar path shapes).
Related errors
- not a valid host, subnet, or domain
- record name is required
- record type is required
- zone name is required
- invalid domain name
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/fdf3919513e7b296.
Report an issue: GitHub.