{"record":{"id":"3e7a079d34aa7bce","repo":"OpenNHP/opennhp","slug":"cluster-q-instance-d-invalid-port-d","errorCode":null,"errorMessage":"cluster %q instance #%d: invalid port %d","messagePattern":"cluster %q instance #(.+?): invalid port (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/agent/cluster.go","lineNumber":159,"sourceCode":"\t\t\tcfg.Name, cfg.PubKeyBase64, err)\n\t}\n\n\tsc := &ServerCluster{\n\t\tPublicKeyBase64: cfg.PubKeyBase64,\n\t\tName:            cfg.Name,\n\t\tSticky:          cfg.StickyOrDefault(),\n\t\tinstances:       make([]*ServerInstance, 0, len(cfg.Instances)),\n\t}\n\n\tfor i, ic := range cfg.Instances {\n\t\thost := ic.Host\n\t\tip := ic.Ip\n\t\tif host == \"\" && ip == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"cluster %q instance #%d: must set either Host or Ip\",\n\t\t\t\tcfg.Name, i)\n\t\t}\n\t\tif ic.Port <= 0 {\n\t\t\treturn nil, fmt.Errorf(\"cluster %q instance #%d: invalid port %d\",\n\t\t\t\tcfg.Name, i, ic.Port)\n\t\t}\n\t\tpeer := &core.UdpPeer{\n\t\t\tPubKeyBase64: cfg.PubKeyBase64,\n\t\t\tHostname:     host,\n\t\t\tIp:           ip,\n\t\t\tPort:         ic.Port,\n\t\t\tType:         core.NHP_SERVER,\n\t\t\tExpireTime:   cfg.ExpireTime,\n\t\t}\n\t\tdisplayHost := host\n\t\tif displayHost == \"\" {\n\t\t\tdisplayHost = ip\n\t\t}\n\t\tsc.instances = append(sc.instances, &ServerInstance{\n\t\t\tpeer:     peer,\n\t\t\tweight:   ic.Weight,\n\t\t\thostPort: fmt.Sprintf(\"%s:%d\", displayHost, ic.Port),","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/agent/cluster.go#L141-L177","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Set a valid positive Port (1-65535, typically 10581 for NHP UDP) on the flagged instance in server.toml.","Verify the TOML key is exactly Port so it maps to the InstanceConfig field rather than decoding as 0.","Check the rendered config template output for an empty port placeholder.","Correct the test/helper (e.g. buildTwoInstanceCluster) if a programmatically built instance forgot the port."],"exampleFix":"// before\n[[Servers.Instances]]\nIp = \"10.0.0.5\"\n# Port missing -> decodes as 0\n\n// after\n[[Servers.Instances]]\nIp = \"10.0.0.5\"\nPort = 10581","handlingStrategy":"validation","validationCode":"if ic.Port <= 0 || ic.Port > 65535 {\n    return fmt.Errorf(\"instance %d: port must be 1-65535, got %d\", i, ic.Port)\n}","typeGuard":null,"tryCatchPattern":"clusters, err := buildCluster(cfg)\nif err != nil {\n    return fmt.Errorf(\"invalid server.toml: %w\", err)\n}","preventionTips":["Always set Port explicitly on every [[Servers.Instances]] entry.","Watch for TOML key case mismatches (Port vs port) that decode as 0.","Validate ports in CI by decoding the TOML and asserting Port > 0."],"tags":["config","validation","go","port"],"backgroundTag":"invalid-config-value","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}