OpenNHP/opennhp · error

cluster instance # : must set either Host or Ip

Error message

cluster %q instance #%d: must set either Host or Ip

What it means

buildCluster validates each [[Servers]] instance entry in server.toml before creating a UdpPeer. When an instance defines neither Host nor Ip, there is no address to knock against, so the cluster cannot be built and a descriptive error naming the cluster and instance index is returned. This is a config-validation guard to fail fast at startup instead of producing an unresolvable peer.

Solutions

  1. Set either Host (DNS name) or Ip for every instance in the cluster's [[Servers.Instances]] in server.toml.
  2. Check the rendered config in deploy/configs/ or /etc/opennhp/agent to confirm the address variable (e.g. ${NHP_SERVER_HOST}) was not empty at render time.
  3. If building the Config in code, populate ic.Host or ic.Ip before calling buildCluster.
  4. Run the agent once with debug logging to see which cluster name and instance index failed, then fix that block.

Example fix

// before
[[Servers.Instances]]
Port = 10581
PubKeyBase64 = "..."

// after
[[Servers.Instances]]
Ip = "10.0.0.5"   # or Host = "nhp.example.org"
Port = 10581
PubKeyBase64 = "..."
Defensive patterns

Strategy: validation

Validate before calling

for i, ic := range cfg.Instances {
    if ic.Host == "" && ic.Ip == "" {
        return fmt.Errorf("instance %d of cluster %q needs Host or Ip", i, cfg.Name)
    }
}

Try / catch

clusters, err := buildCluster(cfg)
if err != nil {
    return fmt.Errorf("load server.toml: %w", err)
}

Prevention

When it happens

Trigger: Calling buildCluster (directly or via buildTwoInstanceCluster, updateServerPeers, or FindServerClusterFromResource paths in tests) with a cfg.Instances[i] where both Host=="" and Ip=="".

Common situations: Hand-edited server.toml where a [[Servers.Instances]] block has a Port and PubKey but the Host/Ip line was deleted or commented out; template rendering with envsubst where the address variable was empty in the secrets/config template; programmatic Config construction in tests omitting both fields.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/c1d11bcb8697890e. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/agent/cluster.go:155

			cfg.Name, cfg.PubKeyBase64)
	}
	if err := cfg.LoadBalance.Validate(); err != nil {
		return nil, fmt.Errorf("cluster %q (%s): %w",
			cfg.Name, cfg.PubKeyBase64, err)
	}

	sc := &ServerCluster{
		PublicKeyBase64: cfg.PubKeyBase64,
		Name:            cfg.Name,
		Sticky:          cfg.StickyOrDefault(),
		instances:       make([]*ServerInstance, 0, len(cfg.Instances)),
	}

	for i, ic := range cfg.Instances {
		host := ic.Host
		ip := ic.Ip
		if host == "" && ip == "" {
			return nil, fmt.Errorf("cluster %q instance #%d: must set either Host or Ip",
				cfg.Name, i)
		}
		if ic.Port <= 0 {
			return nil, fmt.Errorf("cluster %q instance #%d: invalid port %d",
				cfg.Name, i, ic.Port)
		}
		peer := &core.UdpPeer{
			PubKeyBase64: cfg.PubKeyBase64,
			Hostname:     host,
			Ip:           ip,
			Port:         ic.Port,
			Type:         core.NHP_SERVER,
			ExpireTime:   cfg.ExpireTime,
		}
		displayHost := host
		if displayHost == "" {
			displayHost = ip
		}

View on GitHub (pinned to 6e04ca5ff0)