OpenNHP/opennhp · error

cluster instance # : invalid port

Error message

cluster %q instance #%d: invalid port %d

What it means

After confirming an instance has an address, buildCluster validates the port. Any Port <= 0 is invalid (Go's config decode may yield 0 when the field is absent), so the cluster cannot form a usable UdpPeer and an error with the cluster name, instance index, and offending port value is returned.

Solutions

  1. Set a valid positive Port (1-65535, typically 10581 for NHP UDP) on the flagged instance in server.toml.
  2. Verify the TOML key is exactly Port so it maps to the InstanceConfig field rather than decoding as 0.
  3. Check the rendered config template output for an empty port placeholder.
  4. Correct the test/helper (e.g. buildTwoInstanceCluster) if a programmatically built instance forgot the port.

Example fix

// before
[[Servers.Instances]]
Ip = "10.0.0.5"
# Port missing -> decodes as 0

// after
[[Servers.Instances]]
Ip = "10.0.0.5"
Port = 10581
Defensive patterns

Strategy: validation

Validate before calling

if ic.Port <= 0 || ic.Port > 65535 {
    return fmt.Errorf("instance %d: port must be 1-65535, got %d", i, ic.Port)
}

Try / catch

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

Prevention

When it happens

Trigger: buildCluster iterating cfg.Instances and hitting ic.Port <= 0 — typically a [[Servers.Instances]] entry with Port omitted, set to 0, or set to a negative number.

Common situations: Copy-pasting a server.toml block and forgetting the Port line; typo'd TOML key (e.g. port vs Port) so it decodes as 0; envsubst template where the port variable was empty; misreading that ports must be positive (1-65535).

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at endpoints/agent/cluster.go:159

			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
		}
		sc.instances = append(sc.instances, &ServerInstance{
			peer:     peer,
			weight:   ic.Weight,
			hostPort: fmt.Sprintf("%s:%d", displayHost, ic.Port),

View on GitHub (pinned to 6e04ca5ff0)