Lungi Ngidi bowls to Kusal Mendis . AFP/RODGER BOSCH
Mendis made 56 in a Sri Lankan total of 225, which was boosted by an eighth wicket stand of 61 off 53 balls between Priyamal Perera and Isuru Udana.
Even so, Sri Lanka fell three balls short of batting out a full 50 overs, continuing a sequence going back to October 2018.
The only time in their most recent eight matches when they were not bowled out was in the rain-shortened third match of the current series when they were well short of the required run rate when play was halted.
Mendis played a measured innings in making his second half-century of a series in which none of his fellow top-order batsmen reached the 50 mark.
He was needlessly run out after a mix-up with Priyamal Perera in the 35th over at a time when he could reasonably have been expected to start accelerating. He faced 84 balls and hit three fours.
Udana, the only other Sri Lankan to hit a half-century, again made a lively tail-end contribution, hitting 32 off 29 balls before he and Priyamal Perera fell off successive deliveries from Kagiso Rabada in the penultimate over. Rabada finished with three for 50.
Leg-spinner Imran Tahir, in his final one-day international in South Africa, took two for 33, while fast bowler Anrich Nortje took two for 35.
South Africa are seeking to complete a 5-0 clean sweep.
Download our app and read this and other great stories on the move. Available for Android and iOS.