OpenNHP/opennhp · critical
private key parse error
Error message
private key parse error %v
What it means
UdpDevice.Start decodes the device's private key from config (PrivateKeyBase64) using base64.StdEncoding before constructing the core device. If the configured string is not valid standard base64 (or empty after trimming), the decode fails, the error is logged, and Start aborts with 'private key parse error <detail>'. The device cannot run without a valid identity key.
Solutions
- Regenerate a proper key pair with `nhp-device keygen` and paste the privateKey value into config.toml PrivateKeyBase64
- Ensure the value is exact standard base64 with no quotes, whitespace or line breaks
- Check that the config template/environment actually rendered the key (no empty ${VAR})
- Verify you are editing the config file the process actually loads
Example fix
// before (config.toml) privateKeyBase64 = "" // after (config.toml) privateKeyBase64 = "MC4CAQAwBQYDK2VwBCIEIJ..." # output of `nhp-device keygen --curve --json`
Defensive patterns
Strategy: validation
Validate before calling
const raw = config.privateKeyBase64;
if (!raw || Buffer.from(raw, 'base64').toString('base64') !== raw) {
throw new Error('config privateKeyBase64 is missing or not valid standard base64');
} Type guard
const isValidBase64 = (s) => typeof s === 'string' && s.length > 0 && /^[A-Za-z0-9+/]+={0,2}$/.test(s) && Buffer.from(s, 'base64').toString('base64') === s; Try / catch
if err := device.Start(); err != nil {
if strings.HasPrefix(err.Error(), "private key parse error") {
// regenerate key, fix config, then restart
}
return err
} Prevention
- Provision keys only via `nhp-device keygen` output
- Validate config.toml at deploy time (base64-decode every key field)
- Render templates with strict env var checks so keys cannot end up empty
- Strip whitespace/newlines when pasting keys into config
When it happens
Trigger: Starting nhp-db (`nhp-device run` with a config whose PrivateKeyBase64 in config.toml is empty, truncated, contains whitespace/newlines, was generated with URL-safe base64 instead of StdEncoding, or is not base64 at all.
Common situations: Hand-editing config.toml and corrupting the key; pasting a hex key into a base64 field; env-subst templates leaving ${...} unresolved; switching keys generated by different tooling; missing config file defaulting the field to empty.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- private key parse error
- private key parse error
- failed to create device
- server peer config invalid on initial load
- private key parse error
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/be35b51922588b6b.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/db/udpdevice.go:139
// init logger
a.log = log.NewLogger("NHP-DB", logLevel, filepath.Join(ExeDirPath, "logs"), "device")
log.SetGlobalLogger(a.log)
log.Info("=========================================================")
log.Info("=== NHP-DB %s started ===", version.Version)
log.Info("=== REVISION %s ===", version.CommitId)
log.Info("=== RELEASE %s ===", version.BuildTime)
log.Info("=========================================================")
err = a.loadBaseConfig()
if err != nil {
return err
}
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_DB, prk, nil)
if a.device == nil {
log.Critical("failed to create device %v\n", err)
return fmt.Errorf("failed to create device %v", err)
}
a.remoteConnectionMap = make(map[string]*UdpConn)
a.serverPeerMap = make(map[string]*core.UdpPeer)
// load peers
_ = a.loadPeers()
// load TEEs
_ = a.loadTEEs()
a.signals.stop = make(chan struct{})View on GitHub (pinned to 6e04ca5ff0)