OpenNHP/opennhp · error

peer expired (type= , pubkey= )

Error message

peer expired (type=%s, pubkey=%s)

What it means

The peer's public key was found in the pool, but the peer record reports itself expired (Peer.IsExpired). The device treats expiry as an authorization failure: the previously registered agent/server/AC must re-register or be refreshed before its messages are processed. This guards against stale registrations lingering after lease/renewal windows pass.

Solutions

  1. Have the peer re-register (resend NHP_REG/NHP_OTP) to refresh its record, then retry the operation.
  2. Check both hosts' clocks (NTP) — skew beyond the TTL makes valid peers look expired.
  3. Extend or disable the peer TTL in the peer-pool/registration store configuration if long-lived peers are expected.
  4. Purge and re-provision stale entries: restart the dynamic-registration store sync or re-run the key deployment for that peer.

Example fix

// before: agent resumes after TTL lapse with stale registration
// agent
client.Knock(...) // peer expired (type=agent, pubkey=...)
// after: re-register first
client.Register() // refreshes peer record/expiry
client.Knock(...)
Defensive patterns

Strategy: retry

Validate before calling

// client-side: check remaining lease before sending
if time.Now().Unix() > registrationExpiryUnix-60 {
	_ = client.Register() // refresh proactively
}

Try / catch

err := client.SendKnock(server)
if err != nil && strings.Contains(err.Error(), "peer expired") {
	if rerr := client.Register(); rerr == nil {
		err = client.SendKnock(server)
	}
}

Prevention

When it happens

Trigger: An agent registered via NHP_REG whose expiry timestamp passed and that did not re-register; a long-running deployment where peer TTLs in the pool/SQLite store lapsed during downtime; clock skew between nodes making a still-valid peer look expired; a peer removed by a cleanup job while still in use.

Common situations: Agents offline longer than their registration TTL then resuming traffic; system clock jumps (NTP resets, VM snapshots) on the receiving node; server maintenance windows exceeding peer lease duration; expired entries in the dynamic-registration SQLite store never purged or renewed.

Related errors


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

Appendix: source

Thrown at nhp/core/responder.go:510

			// registered via NHP-REG stored in SQLite).
			ppd.device.optionMutex.Lock()
			fallback := ppd.device.option.PeerLookupFallback
			ppd.device.optionMutex.Unlock()
			if fallback != nil && fallback(peerPk, ppd.HeaderType) {
				log.Info("validatePeer: %s peer accepted via fallback, pubkey=%s",
					peerDeviceTypeName, peerPkBase64)
				// Skip expiry/address checks for fallback peers.
				goto peerAccepted
			}
			log.Error("validatePeer: %s peer not found in peer pool, pubkey=%s",
				peerDeviceTypeName, peerPkBase64)
			err = fmt.Errorf("peer not found in peer pool (type=%s, pubkey=%s)", peerDeviceTypeName, peerPkBase64)
			return err
		}

		if peer.IsExpired() {
			log.Error("validatePeer: %s peer expired, pubkey=%s", peerDeviceTypeName, peerPkBase64)
			err = fmt.Errorf("peer expired (type=%s, pubkey=%s)", peerDeviceTypeName, peerPkBase64)
			return err
		}

		if !ppd.ConnData.CheckRecvAddress(ppd.LocalInitTime, ppd.ConnData.RemoteAddr) {
			log.Error("validatePeer: %s peer address mismatch on connection, pubkey=%s, remoteAddr=%s",
				peerDeviceTypeName, peerPkBase64, ppd.ConnData.RemoteAddr)
			err = fmt.Errorf("peer does not match its previous address on this connection (type=%s, pubkey=%s)", peerDeviceTypeName, peerPkBase64)
			return err
		}
		ppd.ConnData.UpdateRecvAddress(ppd.LocalInitTime, ppd.ConnData.RemoteAddr)
		peer.UpdateRecv(ppd.LocalInitTime)
	peerAccepted:
	}

	ppd.RemotePubKey = peerPk
	if ppd.ConnPeerPublicKey != nil {
		copy((*ppd.ConnPeerPublicKey)[:], peerPk)
	}

View on GitHub (pinned to 6e04ca5ff0)