OpenNHP/opennhp · error

: [[Servers]][ ] Name invalid — allowed chars…

Error message

%s: [[Servers]][%d] Name %q invalid — allowed chars: [a-zA-Z0-9._-]

What it means

Cluster-config validation error from Normalize: the entry's Name contains characters outside [a-zA-Z0-9._-] (spaces, unicode, slashes, etc.). Because names are matched against references in resource.toml and used as map keys, any character that complicates exact matching is rejected up front.

Solutions

  1. Rewrite the Name using only letters, digits, dots, underscores and hyphens
  2. Replace spaces with hyphens or underscores
  3. Update any resource.toml references to match the corrected name
Defensive patterns

Strategy: validation

When it happens

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

Appendix: source

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

	}
	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
			// incomplete migration. Refuse to guess which one the
			// operator meant.
			return fmt.Errorf("%s: [[Servers]][%d] (%s) sets both top-level Ip/Hostname/Port and [[Servers.Instances]]; "+
				"pick one form — top-level fields are deprecated, prefer Instances",
				label, i, c.PubKeyBase64)
		case legacy && !hasInstances:
			deprecate("%s: [[Servers]][%d] uses legacy single-server form (Hostname/Ip/Port at top level); "+
				"migrate to [[Servers.Instances]] in server.toml — auto-upgrading for now",

View on GitHub (pinned to 6e04ca5ff0)