OpenNHP/opennhp · error

missing remote peer public key

Error message

missing remote peer public key

What it means

Device.validateMsgData always requires md.PeerPk (the remote peer's static public key) when PrevParserData is nil, regardless of device type. The peer key is needed to verify and encrypt messages for the counterparty; sending without it is impossible.

Solutions

  1. Look up the peer's public key from the device's peer table and set md.PeerPk before sending
  2. Redeploy synchronized peer tables after key rotation (see AGENTS.md key rotation notes)
  3. In tests, generate peer keys via keygen helpers instead of leaving PeerPk nil
  4. Confirm the config file lists the remote peer so the device can resolve its public key

Example fix

// before
md := &MsgData{Msg: msg, RemoteAddr: addr}
// after
peer, ok := dev.GetPeer(remotePubKeyBase64)
if !ok { return errors.New("unknown peer") }
md := &MsgData{Msg: msg, RemoteAddr: addr, PeerPk: peer.PublicKey}
Defensive patterns

Strategy: validation

Validate before calling

if md.PeerPk == nil {
    return errors.New("PeerPk required")
}

Type guard

func hasPeerKey(md *nhpcore.MsgData) bool { return md.PeerPk != nil }

Try / catch

if err := dev.MsgToPacket(md); err != nil && strings.Contains(err.Error(), "missing remote peer public key") {
    return fmt.Errorf("peer %s not in peer table", peerId)
}

Prevention

When it happens

Trigger: Any MsgToPacket or server-side message assembly where MsgData.PeerPk is nil and PrevParserData is nil — even when ConnData or RemoteAddr is correctly set.

Common situations: Loading peer keys from a stale or empty server.toml peer table; key rotation (e.g. after generate-nhp-keys.sh --regenerate) leaving code with the wrong key id; tests building MsgData without a peer key.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/9df98f8e2b3f5f80. Report an issue: GitHub.

Appendix: source

Thrown at nhp/core/initiator.go:50

	ClPkc          bool // 0: non-CL-PKC extented, 1: CL-PKC extended
	ExternalPacket *Packet
	ExternalCookie *[CookieSize]byte
	Message        []byte
	PeerPk         []byte
	EncryptedPktCh chan *MsgAssemblerData
	ResponseMsgCh  chan *PacketParserData
}

func (d *Device) validateMsgData(md *MsgData) (err error) {
	if md.PrevParserData == nil {
		if d.deviceType == NHP_SERVER && md.ConnData == nil {
			err = fmt.Errorf("missing connection data for server")
		} else if d.deviceType != NHP_SERVER && md.RemoteAddr == nil {
			err = fmt.Errorf("missing remote address")
		}

		if md.PeerPk == nil {
			err = fmt.Errorf("missing remote peer public key")
		}
	}

	return err
}

type MsgAssemblerData struct {
	device     *Device
	BasePacket *Packet
	connData   *ConnectionData
	ciphers    *CipherSuite

	deviceEcdh     Ecdh
	ephermeralEcdh Ecdh
	header         Header
	hmacHash       hash.Hash
	chainHash      hash.Hash
	bodyAead       cipher.AEAD

View on GitHub (pinned to 6e04ca5ff0)