OpenNHP/opennhp · critical
private key parse error
Error message
private key parse error %v
What it means
Raised in nhp-server's UDP Start after the listen socket is bound: base64 decoding of config.PrivateKeyBase64 — the server's identity private key — failed. The daemon logs 'private key parse error' and returns, refusing to run with an unusable Noise-protocol identity.
Solutions
- Regenerate keys with the daemon's keygen command (e.g. nhp-serverd keygen --curve --json) and paste the private key field verbatim
- Validate with: echo "$KEY" | base64 -d >/dev/null && echo ok
- Strip quotes, whitespace, and newlines from the configured value
- Confirm you are using the private key, not the public key, and the correct cipher scheme
Example fix
// before privateKeyBase64 = "MFkwEwYHKoZI..." // hex or PEM fragment // after privateKeyBase64 = "O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtB2ik="
Defensive patterns
Strategy: validation
Validate before calling
key, err := base64.StdEncoding.DecodeString(cfg.PrivateKeyBase64)
if err != nil || len(key) != expectedKeyLen {
return fmt.Errorf("privateKeyBase64 invalid: decode=%v len=%d", err, len(key))
} Prevention
- Generate keys only via the daemon's keygen command
- Paste the base64 value exactly as emitted, without quotes/newlines
- Distinguish private vs public key fields
- Confirm the cipher scheme matches the key type
When it happens
Trigger: PrivateKeyBase64 contains whitespace, URL-safe base64 characters (-, _), raw binary pasted as text, or was generated by a tool using a different encoding.
Common situations: Operator pasting a hex or raw key instead of base64; config templating introducing quotes/newlines; keys generated with 'keygen --json' output field mixed up (public pasted as private).
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/abf04d68846bb180.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/udpserver.go:266
Port: s.config.ListenPort,
})
if err != nil {
log.Error("listen error: %v", err)
return fmt.Errorf("listen error %v", err)
}
// retrieve local port
laddr := s.listenConn.LocalAddr()
s.listenAddr, err = net.ResolveUDPAddr(laddr.Network(), laddr.String())
if err != nil {
log.Error("resolve local UDPAddr error: %v", err)
return fmt.Errorf("resolve UDPAddr error %v", err)
}
prk, err := base64.StdEncoding.DecodeString(s.config.PrivateKeyBase64)
if err != nil {
log.Error("private key parse error: %v", err)
return fmt.Errorf("private key parse error %v", err)
}
option := &core.DeviceOptions{
DisableAgentPeerValidation: s.config.DisableAgentValidation,
}
s.device = core.NewDevice(core.NHP_SERVER, prk, option)
if s.device == nil {
log.Critical("failed to create device: %v", err)
return fmt.Errorf("failed to create device %v", err)
}
// Stateless cookie signing key. In a multi-instance cluster all
// nhp-server replicas must share the same value so any of them can
// verify a cookie that a sibling minted. When the operator hasn't
// configured one we mint a random per-process key — fine for a single
// instance, broken for a cluster (the failure is silent: cookies
// minted by replica A don't verify on replica B and the agent's RKN
// stalls until timeout). Always log which mode we're in.View on GitHub (pinned to 6e04ca5ff0)