cilium/cilium · error

failed while updating peer %v:%v with ASN %v: %w

Error message

failed while updating peer %v:%v with ASN %v: %w

What it means

UpdateNeighbor wraps errors from the gobgp UpdatePeer gRPC call. The message includes the OLD peer's address:port and ASN (from oldPeer.Conf), so the wrapped gobgp error is the real cause — commonly the peer was concurrently removed or the update conflicts with server state.

Source

Thrown at pkg/bgp/gobgp/peer.go:46

// UpdateNeighbor will update the existing CiliumBGPNeighbor in the gobgp.BgpServer.
func (g *GoBGPServer) UpdateNeighbor(ctx context.Context, n *types.Neighbor) error {
	oldPeer, err := g.getExistingPeer(ctx, n.Address, n.ASN)
	if err != nil {
		return fmt.Errorf("failed to get existing peer: %w", err)
	}

	newPeer := ToGoBGPPeer(n, oldPeer, n.Address.Is4())

	needsHardReset := g.needsHardReset(oldPeer, newPeer)

	// update peer config
	peerReq := &gobgp.UpdatePeerRequest{
		Peer: ToGoBGPPeer(n, oldPeer, n.Address.Is4()),
	}

	updateRes, err := g.server.UpdatePeer(ctx, peerReq)
	if err != nil {
		return fmt.Errorf("failed while updating peer %v:%v with ASN %v: %w", oldPeer.Conf.NeighborAddress, oldPeer.Transport.RemotePort, oldPeer.Conf.PeerAsn, err)
	}

	// perform full / soft peer reset if necessary
	if needsHardReset || updateRes.NeedsSoftResetIn {
		resetReq := &gobgp.ResetPeerRequest{
			Address:       oldPeer.Conf.NeighborAddress,
			Communication: "Peer configuration changed",
		}
		if !needsHardReset {
			resetReq.Soft = true
			resetReq.Direction = gobgp.ResetPeerRequest_DIRECTION_IN
		}
		if err = g.server.ResetPeer(ctx, resetReq); err != nil {
			return fmt.Errorf("failed while resetting peer %v:%v in ASN %v: %w", oldPeer.Conf.NeighborAddress, oldPeer.Transport.RemotePort, oldPeer.Conf.PeerAsn, err)
		}
	}

	return nil

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Inspect the wrapped %w error from gobgp for the precise rejection reason
  2. Re-check that the peer still exists before updating; if it was removed, Add it again
  3. Avoid changing immutable peer fields in place — delete and re-add the neighbor instead
  4. Retry the update if the failure was a transient gRPC error
  5. Validate that getExistingPeer returned the intended peer (check address/ASN in the message)

Example fix

// before
err := server.UpdateNeighbor(ctx, n) // peer removed concurrently
// after
if _, err := server.getExistingPeer(ctx, n.Address, n.ASN); err != nil {
    err = server.AddNeighbor(ctx, n)
} else {
    err = server.UpdateNeighbor(ctx, n)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := server.getExistingPeer(ctx, n.Address, n.ASN); err != nil {
    return fmt.Errorf("cannot update non-existent peer: %w", err)
}

Try / catch

updateRes, err := g.server.UpdatePeer(ctx, peerReq)
if err != nil {
    if status.Code(err) == codes.NotFound {
        return g.AddNeighbor(ctx, n)
    }
    return fmt.Errorf("failed while updating peer %v:%v with ASN %v: %w", ...)
}

Prevention

When it happens

Trigger: Calling UpdateNeighbor when g.server.UpdatePeer rejects the request — e.g. no peer with that address exists anymore (removed concurrently), invalid peer configuration produced by ToGoBGPPeer, or a gRPC/transport failure.

Common situations: Race between reconciliation deleting and updating the same neighbor; changing fields gobgp disallows updating in place; ASN/port fields of oldPeer zero-valued because the old lookup returned an unexpected peer; control-plane restarting mid-update.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/56f754a1ce48704c. Report an issue: GitHub.