slackhq/nebula · error
relay hostinfo is no longer in the hostmap
Error message
relay hostinfo is no longer in the hostmap
What it means
relayManager.AddRelay links a relay HostInfo into the hostmap under a new local index. unlockedMakePrimary fails if the HostInfo's tunnel was torn down between the caller grabbing it and this call — the hostinfo node is no longer linked into the hostmap. In that case the relay can never carry traffic, so AddRelay returns this error instead of registering a dangling relay.
Source
Thrown at relay_manager.go:247
func AddRelay(l *slog.Logger, relayHostInfo *HostInfo, hm *HostMap, vpnIp netip.Addr, remoteIdx *uint32, relayType int, state int) (uint32, error) {
hm.Lock()
defer hm.Unlock()
for range 32 {
index, err := generateIndex(l)
if err != nil {
return 0, err
}
_, inRelays := hm.Relays[index]
if !inRelays {
// Avoid standing up a relay that can't be used since only the primary hostinfo
// will be pointed to by the relay logic
//TODO: if there was an existing primary and it had relay state, should we merge?
if !hm.unlockedMakePrimary(relayHostInfo) {
// The tunnel was torn down after the caller grabbed relayHostInfo. A relay standing
// on an unlinked hostinfo would never carry traffic, and its Relays entry could
// never be reclaimed since the delete-time cleanup has already run.
return 0, errors.New("relay hostinfo is no longer in the hostmap")
}
hm.Relays[index] = relayHostInfo
newRelay := Relay{
Type: relayType,
State: state,
LocalIndex: index,
PeerAddr: vpnIp,
}
if remoteIdx != nil {
newRelay.RemoteIndex = *remoteIdx
}
relayHostInfo.relayState.InsertRelay(vpnIp, index, &newRelay)
return index, nil
}
}View on GitHub (pinned to dd8f660c0a)
Solutions
- Retry the relay creation: re-establish the connection to the peer (trigger a handshake) and call AddRelay again with the fresh HostInfo.
- Handle the returned error in handleCreateRelayRequest/StartRelays paths by tearing down the pending relay state instead of leaving it Requested.
- Check for root causes of hostinfo eviction (keepalive/ punches dropping, NAT rebinding) if it happens repeatedly.
Example fix
// before
idx, err := rm.AddRelay(hi, vpnIp, idx, nil, RelayEstablished, false)
// after
idx, err := rm.AddRelay(hi, vpnIp, idx, nil, RelayEstablished, false)
if err != nil && err.Error() == "relay hostinfo is no longer in the hostmap" {
// re-handshake with the peer and retry with the new HostInfo
return retryRelay(vpnIp)
} Defensive patterns
Strategy: try-catch
Try / catch
idx, err := rm.AddRelay(hi, vpnIp, idx, nil, RelayEstablished, false)
if err != nil {
if err.Error() == "relay hostinfo is no longer in the hostmap" {
// hostinfo was evicted concurrently; re-handshake and retry
return reestablishAndRetryRelay(vpnIp)
}
return err
} Prevention
- Treat AddRelay's error as 'retry with a fresh HostInfo', not fatal
- Keep the HostInfo alive across relay setup by holding the connection/handshake path
- Log hostmap eviction events to correlate flapping tunnels with relay failures
When it happens
Trigger: Calling AddRelay (directly, via migrateRelayUsed, StartRelays, or handleCreateRelayRequest) with a HostInfo whose hostmap entry was deleted concurrently — e.g. the peer connection dropped or the hostmap entry expired while the relay handshake was in flight.
Common situations: Flapping lighthouse/tunnel connections during relay establishment; handshake timeouts racing relay setup; restarts where the remote hostinfo was evicted; re-using a stale *HostInfo pointer from before a reconnect.
Related errors
- unable to find host
- unable to find host with relay
- failed to generate unique localIndexId
- could not find hostinfo
- hostmap LocalIndex '%v' does not match RelayState LocalIndex
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/5e1117226a6cccb8.
Report an issue: GitHub.