{"record":{"id":"d9e16434c55eea87","repo":"OpenNHP/opennhp","slug":"no-private-key-configured-check-etc-config-toml","errorCode":null,"errorMessage":"no private key configured; check etc/config.toml","messagePattern":"no private key configured; check etc/config\\.toml","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"endpoints/agent/udpagent.go","lineNumber":385,"sourceCode":"\terr = a.loadBaseConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = a.loadDHPConfig()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar prk []byte\n\tif a.config.PrivateKeyBase64 == \"\" {\n\t\t// An empty private key is only acceptable in the register bootstrap\n\t\t// flow (allowMissingConfig): use a throwaway key that ReinitWithKey\n\t\t// replaces immediately after Start returns. For run/dhp this is a\n\t\t// real misconfiguration — fail loudly instead of silently starting\n\t\t// with a random key and empty identity.\n\t\tif !a.allowMissingConfig {\n\t\t\tlog.Error(\"no private key configured in etc/config.toml\")\n\t\t\treturn fmt.Errorf(\"no private key configured; check etc/config.toml\")\n\t\t}\n\t\tprk = core.NewECDH(core.ECC_CURVE25519).PrivateKey()\n\t} else {\n\t\tprk, err = base64.StdEncoding.DecodeString(a.config.PrivateKeyBase64)\n\t\tif err != nil {\n\t\t\tlog.Error(\"private key parse error %v\\n\", err)\n\t\t\treturn fmt.Errorf(\"private key parse error %v\", err)\n\t\t}\n\t}\n\n\ta.device = core.NewDevice(core.NHP_AGENT, prk, nil)\n\tif a.device == nil {\n\t\tlog.Critical(\"failed to create device %v\\n\", err)\n\t\treturn fmt.Errorf(\"failed to create device %v\", err)\n\t}\n\n\t// start device routines\n\ta.device.Start()","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/agent/udpagent.go#L367-L403","documentation":"UdpAgent.Start refuses to boot the agent when no base64 private key is set in etc/config.toml and the agent was not created with allowMissingConfig. The agent's identity (device key pair) is central to knocking and registration, so starting with a random throwaway key silently would break all peer trust. The library throws this to fail loudly on real misconfiguration while still permitting a temporary key flow for registration (allowMissingConfig=true).","triggerScenarios":"Calling Start (via runApp, runDHPApp, runRegisterApp, or RestartAgent) on a UdpAgent whose config.PrivateKeyBase64 is empty and whose allowMissingConfig flag is false.","commonSituations":"Fresh checkout without filling in etc/config.toml; key field accidentally cleared during redeployment; running the agent binary before running keygen; wrong config file path so PrivateKeyBase64 never loads.","solutions":["Run the agent's keygen command (e.g. ./nhp-agentd keygen --curve) and paste the resulting base64 private key into PrivateKeyBase64 in etc/config.toml","Verify the agent actually loads the intended etc/config.toml (check working directory / config path flag)","If the agent is only used for registration with a throwaway key, construct/initialize it with allowMissingConfig enabled so ReinitWithKey can replace the key after Start"],"exampleFix":"// before (etc/config.toml)\n# PrivateKeyBase64 = \"\"\n// after\nPrivateKeyBase64 = \"dJf3...base64key==\"","handlingStrategy":"validation","validationCode":"if agent.config.PrivateKeyBase64 == \"\" && !agent.allowMissingConfig {\n    return fmt.Errorf(\"agent private key missing: run keygen and set PrivateKeyBase64 in etc/config.toml\")\n}","typeGuard":null,"tryCatchPattern":"if err := agent.Start(); err != nil {\n    if strings.Contains(err.Error(), \"no private key configured\") {\n        log.Fatal(\"configure PrivateKeyBase64 in etc/config.toml before starting\")\n    }\n}","preventionTips":["Run keygen during provisioning and template PrivateKeyBase64 into config.toml","Fail fast in deployment scripts if the config field is empty","Use a config linter/startup preflight check before launching the agent"],"tags":["config","go","agent","missing-key"],"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"}