{"record":{"id":"f9a7a2b3f7424e4a","repo":"OpenNHP/opennhp","slug":"s-servers-d-missing-pubkeybase64","errorCode":null,"errorMessage":"%s: [[Servers]][%d] missing PubKeyBase64","messagePattern":"(.+?): \\[\\[Servers\\]\\]\\[(.+?)\\] missing PubKeyBase64","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nhp/common/clusterconfig/clusterconfig.go","lineNumber":147,"sourceCode":"// invocations for assertions. A nil deprecate is treated as no-op.\nfunc Normalize(clusters []*ClusterConfig, opts Options, deprecate func(string, ...any)) error {\n\tif deprecate == nil {\n\t\tdeprecate = func(string, ...any) {}\n\t}\n\tlabel := opts.ConsumerLabel\n\tif label == \"\" {\n\t\tlabel = \"cluster\"\n\t}\n\n\tif len(clusters) == 0 {\n\t\treturn fmt.Errorf(\"%s: no [[Servers]] configured\", label)\n\t}\n\tfor i, c := range clusters {\n\t\tif c == nil {\n\t\t\treturn fmt.Errorf(\"%s: [[Servers]][%d] is nil\", label, i)\n\t\t}\n\t\tif c.PubKeyBase64 == \"\" {\n\t\t\treturn fmt.Errorf(\"%s: [[Servers]][%d] missing PubKeyBase64\", label, i)\n\t\t}\n\t\tif opts.RequireName {\n\t\t\tif c.Name == \"\" {\n\t\t\t\treturn fmt.Errorf(\"%s: [[Servers]][%d] (%s) missing Name — clusters are referenced from resource.toml by Name\",\n\t\t\t\t\tlabel, i, c.PubKeyBase64)\n\t\t\t}\n\t\t\tif len(c.Name) > NameMaxLen {\n\t\t\t\treturn fmt.Errorf(\"%s: [[Servers]][%d] Name %q exceeds %d chars\",\n\t\t\t\t\tlabel, i, c.Name, NameMaxLen)\n\t\t\t}\n\t\t\tif !clusterNameRegex.MatchString(c.Name) {\n\t\t\t\treturn fmt.Errorf(\"%s: [[Servers]][%d] Name %q invalid — allowed chars: [a-zA-Z0-9._-]\",\n\t\t\t\t\tlabel, i, c.Name)\n\t\t\t}\n\t\t}\n\n\t\tlegacy := c.hasLegacyFields()\n\t\thasInstances := len(c.Instances) > 0","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/common/clusterconfig/clusterconfig.go#L129-L165","documentation":"Normalize requires every [[Servers]] cluster entry to carry PubKeyBase64 — the server's base64 public key used to build peer tables and encrypt traffic. An entry without a key is unusable and rejected with its index.","triggerScenarios":"Calling Normalize with clusters[i].PubKeyBase64 == \"\", usually from a TOML [[Servers]] block that omits the PubKeyBase64 key or sets it to an empty string.","commonSituations":"Hand-written server.toml missing the key line; a template variable like ${SERVER_PUB_KEY} left unsubstituted/empty because the secret was absent; copying a cluster block as a template placeholder and not filling it in.","solutions":["Set PubKeyBase64 to the target server's base64 public key (from its keygen output)","Ensure the templating/secret pipeline actually injects the key (check for empty env var / missing secret)","Regenerate and redeploy the key pair if the server's public key changed","Validate the TOML after rendering so empty key fields fail the deploy before Normalize does"],"exampleFix":"// before (server.toml)\n[[Servers]]\nName = \"nhp-server-1\"\n// after\n[[Servers]]\nName = \"nhp-server-1\"\nPubKeyBase64 = \"<base64 public key>\"","handlingStrategy":"validation","validationCode":"for i, c := range clusters {\n    if c.PubKeyBase64 == \"\" {\n        return fmt.Errorf(\"cluster %d (%s) has empty PubKeyBase64 — check secret injection\", i, c.Name)\n    }\n}\nerr := clusterconfig.Normalize(clusters, opts)","typeGuard":null,"tryCatchPattern":"if err := clusterconfig.Normalize(clusters, opts); err != nil {\n    if strings.Contains(err.Error(), \"missing PubKeyBase64\") {\n        return fmt.Errorf(\"server public key missing — did generate-nhp-keys.sh run? %w\", err)\n    }\n    return err\n}","preventionTips":["Run scripts/generate-nhp-keys.sh before rendering configs so keys exist","Fail template rendering if ${SERVER_PUB_KEY} substitutes to an empty string","Render-time check: reject configs where any PubKeyBase64 is blank"],"tags":["config","crypto","toml"],"backgroundTag":"missing-required-config-field","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"}