OpenNHP/opennhp · error

: [[Servers]][ ] and [[Servers]][ ] share PubKeyBase64 —…

Error message

%s: [[Servers]][%d] and [[Servers]][%d] share PubKeyBase64 %s — merge them into one cluster with multiple Instances

What it means

Cluster-config validation error from Normalize's duplicate-pubkey pass: two distinct [[Servers]] entries declare the same PubKeyBase64. Because peers are keyed by public key in device.peerMap, duplicates would race for one slot and cause a mysterious 'wrong instance answered' at runtime, so the collision is surfaced at load time with both indexes and the shared key.

Solutions

  1. Merge the two entries into a single [[Servers]] block listing each endpoint under [[Servers.Instances]]
  2. Regenerate keys if two genuinely different servers accidentally share a key pair
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at nhp/common/clusterconfig/clusterconfig.go:217 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/d35f9a84d5e42860. Report an issue: GitHub.

Appendix: source

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

				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 — "+
				"merge them into one cluster with multiple Instances",
				label, prev, i, c.PubKeyBase64)
		}
		seenPK[c.PubKeyBase64] = i
	}

	// Duplicate Name detection — only meaningful when names are
	// required (and therefore non-empty). For consumers that leave Name
	// optional, blank names are allowed to repeat.
	if opts.RequireName {
		seenName := make(map[string]int, len(clusters))
		for i, c := range clusters {
			if prev, ok := seenName[c.Name]; ok {
				return fmt.Errorf("%s: [[Servers]][%d] and [[Servers]][%d] share Name %q",
					label, prev, i, c.Name)
			}
			seenName[c.Name] = i
		}

View on GitHub (pinned to 6e04ca5ff0)