OpenNHP/opennhp · error

: [[Servers]][ ] ( ) missing Name — clusters are referenced…

Error message

%s: [[Servers]][%d] (%s) missing Name — clusters are referenced from resource.toml by Name

What it means

When opts.RequireName is set, Normalize additionally demands a non-empty Name per cluster, because clusters are referenced from resource.toml by Name rather than by key or index. An anonymous cluster cannot be referenced and is rejected, with the entry's key echoed for identification.

Solutions

  1. Add a unique Name to every [[Servers]] block in the cluster config
  2. Use the same Name string in resource.toml cluster references so lookups resolve
  3. Keep each Name within NameMaxLen — check the surrounding validation for the length limit
  4. Update config templates so future deployments always emit Name alongside PubKeyBase64

Example fix

// before (server.toml)
[[Servers]]
PubKeyBase64 = "<key>"
// after
[[Servers]]
Name = "nhp-server-1"
PubKeyBase64 = "<key>"
Defensive patterns

Strategy: validation

Validate before calling

for i, c := range clusters {
    if c.Name == "" {
        return fmt.Errorf("cluster %d needs a Name (referenced from resource.toml)", i)
    }
}
err := clusterconfig.Normalize(clusters, clusterconfig.NormalizeOptions{RequireName: true, ...})

Try / catch

if err := clusterconfig.Normalize(clusters, opts); err != nil {
    if strings.Contains(err.Error(), "missing Name") {
        return fmt.Errorf("multi-cluster configs require per-cluster Name fields: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Normalize with RequireName=true (e.g. from normalizeClusters for multi-cluster deployments) and clusters[i].Name == "".

Common situations: Upgrading from a single-cluster config where Name was optional to the multi-cluster format that requires it; docker-compose demo configs copied without adding Name; resource.toml referencing clusters by Name while server.toml entries lack the field.

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/7f6a945be69e415a. Report an issue: GitHub.

Appendix: source

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

	}
	label := opts.ConsumerLabel
	if label == "" {
		label = "cluster"
	}

	if len(clusters) == 0 {
		return fmt.Errorf("%s: no [[Servers]] configured", label)
	}
	for i, c := range clusters {
		if c == nil {
			return fmt.Errorf("%s: [[Servers]][%d] is nil", label, i)
		}
		if c.PubKeyBase64 == "" {
			return fmt.Errorf("%s: [[Servers]][%d] missing PubKeyBase64", label, i)
		}
		if opts.RequireName {
			if c.Name == "" {
				return fmt.Errorf("%s: [[Servers]][%d] (%s) missing Name — clusters are referenced from resource.toml by Name",
					label, i, c.PubKeyBase64)
			}
			if len(c.Name) > NameMaxLen {
				return fmt.Errorf("%s: [[Servers]][%d] Name %q exceeds %d chars",
					label, i, c.Name, NameMaxLen)
			}
			if !clusterNameRegex.MatchString(c.Name) {
				return fmt.Errorf("%s: [[Servers]][%d] Name %q invalid — allowed chars: [a-zA-Z0-9._-]",
					label, i, c.Name)
			}
		}

		legacy := c.hasLegacyFields()
		hasInstances := len(c.Instances) > 0

		switch {
		case legacy && hasInstances:
			// Both forms in one entry is almost certainly an

View on GitHub (pinned to 6e04ca5ff0)