OpenNHP/opennhp · error
relay: server # instance # missing host
Error message
relay: server #%d instance #%d missing host
What it means
normalize requires every instance to have a non-empty host; this error reports the server and instance indices. Without a host the relay has no address to forward upstream traffic to, so the instance entry is invalid.
Solutions
- Set host in the flagged [[Servers.Instances]] block to the upstream server's hostname or IP
- If rendering from templates, verify the host variable is populated in the deploy environment
- Remove instance blocks that are placeholders and not actually intended
Example fix
// before [[Servers.Instances]] host = "" port = 10161 // after [[Servers.Instances]] host = "10.0.0.5" port = 10161
Defensive patterns
Strategy: validation
Validate before calling
for i, s := range cfg.Servers {
for j, inst := range s.Instances {
if strings.TrimSpace(inst.Host) == "" {
return fmt.Errorf("server #%d instance #%d host empty", i, j)
}
}
} Type guard
func hostSet(inst relay.Instance) bool { return strings.TrimSpace(inst.Host) != "" } Try / catch
if err := cfg.Normalize(); err != nil {
if strings.Contains(err.Error(), "missing host") {
return fmt.Errorf("set host in every [[Servers.Instances]]: %w", err)
}
return err
} Prevention
- Fail template rendering when the host variable is empty instead of emitting host = ""
- Validate rendered configs in CI before deploy
- Use hostnames/IPs from a single source of truth to avoid blanks
When it happens
Trigger: The Nth [[Servers.Instances]] block omits the host key or sets it to an empty string (""), e.g. host = "" or a template variable that rendered empty during normalize.
Common situations: Template rendering with an unset env var produced host = ""; operator deleted the host line accidentally; copy-pasted an instance block and blanked the host intending to fill it later.
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
- relay: privateKeyBase64 must be set in config
- relay: no upstream configured; add at least one [[Servers]]…
- relay: server # missing publicKeyBase64
- relay: server # (fingerprint ) has no [[Servers.Instances]]
- relay: server # instance # missing or invalid port
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/315f604131f2003b.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/relay/config.go:246
if c.PubKeyBase64 == "" {
return fmt.Errorf("relay: server #%d missing publicKeyBase64", i)
}
fp, err := utils.PubKeyFingerprintFromBase64(c.PubKeyBase64)
if err != nil {
return fmt.Errorf("relay: server #%d publicKeyBase64 invalid: %w", i, err)
}
if dup, ok := seenFP[fp]; ok {
return fmt.Errorf("relay: server #%d and #%d share the same publicKeyBase64 (fingerprint %s)", dup, i, fp)
}
seenFP[fp] = i
if len(c.Instances) == 0 {
return fmt.Errorf("relay: server #%d (fingerprint %s) has no [[Servers.Instances]]", i, fp)
}
for j := range c.Instances {
inst := &c.Instances[j]
if inst.Host == "" {
return fmt.Errorf("relay: server #%d instance #%d missing host", i, j)
}
if inst.Port <= 0 {
return fmt.Errorf("relay: server #%d instance #%d missing or invalid port", i, j)
}
addr := fmt.Sprintf("%s:%d", inst.Host, inst.Port)
// Scope to this server's pubkey: same identity reusing an
// address is the copy-paste error we reject; a sibling
// identity on the same address is allowed (see seenAddr docs).
addrKey := fp + "@" + addr
if dup, ok := seenAddr[addrKey]; ok {
return fmt.Errorf("relay: server #%d instance #%d address %s already claimed by server #%d instance #%d under the same publicKeyBase64 (fingerprint %s)",
i, j, addr, dup.server, dup.instance, fp)
}
seenAddr[addrKey] = addrOrigin{server: i, instance: j}
if inst.Weight <= 0 {
inst.Weight = 1
}
}View on GitHub (pinned to 6e04ca5ff0)