OpenNHP/opennhp · error

: [[Servers]][ ] instance # : Host and Ip both empty

Error message

%s: [[Servers]][%d] instance #%d: Host and Ip both empty

What it means

Cluster-config validation error from Normalize while iterating a server's Instances: an instance declares neither Host nor Ip, so there is no address to dial. The instance index and server entry are included in the message to locate the empty block in server.toml.

Solutions

  1. Set Host (FQDN) or Ip on the flagged [[Servers.Instances]] entry
  2. Remove the instance block entirely if the endpoint is no longer used
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at nhp/common/clusterconfig/clusterconfig.go:199 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at nhp/common/clusterconfig/clusterconfig.go:199

				Ip:     c.Ip,
				Port:   c.Port,
				Weight: 1,
			}}
			// Zero the legacy fields so downstream code never sees both.
			c.Hostname, c.Ip, c.Port = "", "", 0
		case !legacy && !hasInstances:
			return fmt.Errorf("%s: [[Servers]][%d] (%s) has no instances", label, i, c.PubKeyBase64)
		}

		if err := c.LoadBalance.Validate(); err != nil {
			return fmt.Errorf("%s: [[Servers]][%d] (%s): %w", label, i, c.PubKeyBase64, err)
		}
		c.LoadBalance = c.LoadBalance.Normalize()

		for j := range c.Instances {
			inst := &c.Instances[j]
			if inst.Host == "" && inst.Ip == "" {
				return fmt.Errorf("%s: [[Servers]][%d] instance #%d: Host and Ip both empty", label, i, j)
			}
			if inst.Port <= 0 {
				return fmt.Errorf("%s: [[Servers]][%d] instance #%d: invalid Port %d", label, i, j, inst.Port)
			}
			if inst.Weight <= 0 {
				inst.Weight = 1
			}
		}
	}

	// Duplicate pubkey detection — two clusters with the same pubkey
	// would race for the same slot in device.peerMap. Catch it here
	// so the error is obvious at load rather than as a mysterious
	// "wrong instance answered" at runtime.
	seenPK := make(map[string]int, len(clusters))
	for i, c := range clusters {
		if prev, ok := seenPK[c.PubKeyBase64]; ok {
			return fmt.Errorf("%s: [[Servers]][%d] and [[Servers]][%d] share PubKeyBase64 %s — "+

View on GitHub (pinned to 6e04ca5ff0)