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

  1. Pass the exact non-empty cluster address returned by List/Create
  2. Validate or default the config field before calling Delete
  3. 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

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


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/24dc9c01d9411bee. Report an issue: GitHub.