netbirdio/netbird · warning
clusterAddress is required
Error message
clusterAddress is required
What it means
Client-side guard in ReverseProxyClustersAPI.Delete against an empty cluster address. url.PathEscape("") returns an empty string, which would collapse the DELETE path onto the collection endpoint /api/reverse-proxies/clusters and hit the wrong route. The error prevents that accidental request before any HTTP call is made.
Source
Thrown at shared/management/client/rest/reverse_proxy_clusters.go:41
return nil, err
}
if resp.Body != nil {
defer resp.Body.Close()
}
ret, err := parseResponse[[]api.ProxyCluster](resp)
return ret, err
}
// Delete removes every self-hosted (BYOP) proxy registration for the given
// cluster address owned by the calling account. Shared clusters operated by
// NetBird cannot be deleted via this endpoint; the server returns 404 / 400
// for cluster addresses the account does not own.
func (a *ReverseProxyClustersAPI) Delete(ctx context.Context, clusterAddress string) error {
// Guard against the empty input: url.PathEscape("") returns "" which
// would collapse the request URL onto the collection endpoint and
// silently delete nothing (or 405 depending on routing).
if clusterAddress == "" {
return errors.New("clusterAddress is required")
}
resp, err := a.c.NewRequest(ctx, "DELETE", "/api/reverse-proxies/clusters/"+url.PathEscape(clusterAddress), nil, nil)
if err != nil {
return err
}
if resp.Body != nil {
defer resp.Body.Close()
}
return nil
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Pass the exact non-empty cluster address returned by List/Create
- Validate or default the config field before calling Delete
- Skip and log when the address is empty instead of calling
Example fix
// before
err := restClient.ReverseProxyClusters.Delete(ctx, os.Getenv("BYOP_CLUSTER"))
// after
addr := os.Getenv("BYOP_CLUSTER")
if addr == "" {
return fmt.Errorf("BYOP_CLUSTER is not set")
}
err := restClient.ReverseProxyClusters.Delete(ctx, addr) Defensive patterns
Strategy: validation
Validate before calling
if clusterAddress == "" {
return fmt.Errorf("clusterAddress is required before deleting a BYOP cluster")
}
err := restClient.ReverseProxyClusters.Delete(ctx, clusterAddress) Try / catch
if err := restClient.ReverseProxyClusters.Delete(ctx, addr); err != nil {
if err.Error() == "clusterAddress is required" {
// config bug: the address never made it into this code path
}
return err
} Prevention
- Validate required string arguments at the config boundary, not at the HTTP call
- Source cluster addresses from List/Create output rather than hand-typed config
- Fail fast on unset env vars in deployment scripts
When it happens
Trigger: Calling Delete(ctx, "") because the variable holding the cluster address was never set, a struct/config field was left empty, or a loop iterated over an unset field.
Common situations: CI/Terraform scripts templating the address from an unset variable; YAML config with a missing byop.clusterAddress key; helper wrappers that drop the argument.
Related errors
- tokenID is required
- service name is required
- service name exceeds maximum length of 255 characters
- at least one target is required
- private services require at least one access group
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/24dc9c01d9411bee.
Report an issue: GitHub.