OpenNHP/opennhp · critical
no private key configured; check etc/config.toml
Error message
no private key configured; check etc/config.toml
What it means
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).
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
Example fix
// before (etc/config.toml) # PrivateKeyBase64 = "" // after PrivateKeyBase64 = "dJf3...base64key=="
Defensive patterns
Strategy: validation
Validate before calling
if agent.config.PrivateKeyBase64 == "" && !agent.allowMissingConfig {
return fmt.Errorf("agent private key missing: run keygen and set PrivateKeyBase64 in etc/config.toml")
} Try / catch
if err := agent.Start(); err != nil {
if strings.Contains(err.Error(), "no private key configured") {
log.Fatal("configure PrivateKeyBase64 in etc/config.toml before starting")
}
} Prevention
- 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
When it happens
Trigger: Calling Start (via runApp, runDHPApp, runRegisterApp, or RestartAgent) on a UdpAgent whose config.PrivateKeyBase64 is empty and whose allowMissingConfig flag is false.
Common situations: 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.
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/d9e16434c55eea87.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/agent/udpagent.go:385
err = a.loadBaseConfig()
if err != nil {
return err
}
err = a.loadDHPConfig()
if err != nil {
return err
}
var prk []byte
if a.config.PrivateKeyBase64 == "" {
// An empty private key is only acceptable in the register bootstrap
// flow (allowMissingConfig): use a throwaway key that ReinitWithKey
// replaces immediately after Start returns. For run/dhp this is a
// real misconfiguration — fail loudly instead of silently starting
// with a random key and empty identity.
if !a.allowMissingConfig {
log.Error("no private key configured in etc/config.toml")
return fmt.Errorf("no private key configured; check etc/config.toml")
}
prk = core.NewECDH(core.ECC_CURVE25519).PrivateKey()
} else {
prk, err = base64.StdEncoding.DecodeString(a.config.PrivateKeyBase64)
if err != nil {
log.Error("private key parse error %v\n", err)
return fmt.Errorf("private key parse error %v", err)
}
}
a.device = core.NewDevice(core.NHP_AGENT, prk, nil)
if a.device == nil {
log.Critical("failed to create device %v\n", err)
return fmt.Errorf("failed to create device %v", err)
}
// start device routines
a.device.Start()View on GitHub (pinned to 6e04ca5ff0)