I am adding manipulated Accounts to a Set multiple times and update it. It fails due to a Duplicate id in list exception. What should be impossible, because the values are coming from a set. After some research I think it is tightly coupled to Can I use set instead of List to resolve the duplicate id issue
But I feel like the hashes should be updated since I am working on the same account reference meaning the account I add is the exact same that it already contains. The fact that the set has a size of 1 underlines this, converting it to a list I get a size of 2. What is definitely a bug and can't be explained with hashes.
Account a = new Account(Name='a');
insert a;
Set<Account> accountSet = new Set<Account>();
accountSet.add(a);
a.BillingCity = 'Foo'; // this makes it fail later
accountSet.add(a);
update new List<Account>(accountSet);
Line: 9, Column: 1 System.ListException: Duplicate id in list: 0015400000DuAR7AAN
So I started debugging it. The weirdest thing about it is, that if I debug the set once it gets recalculated and cleaned up internally and it doesn't fail anymore.
System.debug(accountSet.size()); // 1
// System.debug(accountSet); // Comment in and it stops failing
List<Account> accountList = new List<Account>(accountSet);
System.debug(accountList.size()); // 2
System.debug(accountList); // two equivalent accounts
Converting the list to a map to get it's unique values resulted in this exception:
System.ListException: Row with duplicate Id at index: 1
Summary
If I would not do any dml I would never recognize that there is a duplicate value in my list, what might lead to hardly traceable bugs.
It seems to be only related to SObjects (custom and standard) since I was not able to reproduce it with a class.
I just wanted to share this with the community hoping to save you a couple hours of debugging and hope we can manage a fix soon. I guess the simplest workaround so far is using a Map as Adrian described here.