Correct, that is partly because the end-condition was not proper. Here I fixed that:
ClearAll[CanonicalPairs,TrySwitch,TotalDistance,TrySwitch,TryAllSubsets,FindPairs]
CanonicalPairs[conns_List]:=Sort[Sort/@conns]
TotalDistance[pts_List,conns_List]:=Total[Norm[N[pts[[#1]]-pts[[#2]]]]&@@@conns]
TrySwitch[pts_List,conns_List,indices_List]:=Module[{orig,newconns,subsets,ids},
orig=CanonicalPairs[conns[[indices]]];
ids=Partition[#,2]&/@Permutations[Flatten[orig]];
ids=DeleteDuplicates[CanonicalPairs/@ids];
ids=TakeSmallestBy[ids,TotalDistance[pts,#]&,1][[1]];
newconns=Delete[conns,List/@indices];
newconns~Join~ids
]
TryAllSubsets[pts_List,conns_List,subsets_List]:=Module[{inconns,tmp},
inconns=CanonicalPairs[conns];
Do[
tmp=CanonicalPairs[TrySwitch[pts,inconns,s]];
If[tmp=!=inconns,Return[tmp,Module]];
,
{s,subsets}
];
Return[inconns]
]
TrySwitchAll[pts_List,conns_List]:=Module[{subsets},
subsets=Subsets[Range[Length[conns]],{2}];
NestWhile[TryAllSubsets[pts,#,subsets]&,conns,(UnsameQ@@(TotalDistance[pts,#]&/@{##}))&,3,1000]
]
FindPairs[pts_List]:=Module[{candidates,out,tmp,left},If[EvenQ[Length[pts]]\[And]Length[pts]>=2,TrySwitchAll[pts,Partition[Range[Length[pts]],2]],Print["Even number of points >=2 needed!"]]]
This is much neater code, but works in a similar way. It tries switching pairs (that is the '2' inside TrySwitchAll) until it stabilises. But sometimes, one needs to swap a triplet (3), or quadruplet (4) to get to the minimum (rare, but can happen).
Basically I'm tickling the partial solution, but what one sometimes needs is a huge kick to get it out of its local minimum.
See e.g. this example:
pts = {{57.526218026559405`,
15.570452206207037`}, {90.54332967253814`,
52.25381104673323`}, {32.476740815657735`,
7.28878961340456`}, {91.39816425481379`,
37.81652745685858`}, {19.24680608590677`,
95.04441305558967`}, {83.85131355308184`,
58.07174181385142`}, {91.42216182515247`,
25.28663683844907`}, {71.81082383731945`, 10.795462957661243`}};
out = FindPairs[pts]
TotalDistance[pts, out]
Graphics[{Red, Point[pts], Black, Line[pts[[#]] & /@ out]}]

One needs to swap all 4 of them together to get the real minimum:

O btw, I never claimed that this algorithm was perfect, but it should give reasonable (local) minima quite quickly. I was aware that there can be local minima... I'm not sure if you can get the real minimum without a very convoluted algorithm that takes lots and lots of time...