27

Am not doing anything fancy, just trying to use contains method of list.

List<Id> myIdList = new List<Id>();
myIdList.add('0060E000008PdMk');

Id oppId ='0060E000008PdMk';   


System.debug(myIdList.contains(oppId)); //Returns false

To my surprise, I spent a few hours debugging and came with this problematic code. Are we not supposed to use contains for List<Id> ?

Changing the type from List<Id> to List<String> makes my code run, but I dont have any clue why it does?

Can anyone shed some light?

UPDATE : As per the suggestion of sfdcfox I have raised a case with SF support. Case number "19522568". I will keep you guys updated with the results.

UPDATE 2 : Salesforce reached out to me for this,

A bug W-4884673 already exist for this issue. SF R&D team is working on the same. Known issue link for reference: https://success.salesforce.com/issues_view?Id=a1p3A000000AT9c

There isn't any ETA for this to be fixed, so the case will be closed as "bug fix submitted"

UPDATE 3 : This has now been resolved

5
  • I'd be curious to see what happens if you debug the list itself, or debug oppId == myIdList[0] – Derek F Jul 10 '18 at 15:29
  • oppId == myIdList[0] returned true. – Pranay Jaiswal Jul 10 '18 at 15:32
  • 1
    Interesting that Apex using .hashCode() for contains differs from Java List that uses .equals() – Daniel Ballinger Jul 10 '18 at 22:15
  • According to the "known issue" cited in Update 2, above, this has been fixed in "Spring '19". However, we are seeing this issue on newly created scratch orgs. – Phil W Apr 25 '19 at 14:19
  • 1
    Guess who is back - success.salesforce.com/… – kurunve Jan 31 '20 at 8:20
12

Looks like this bug System.hashCode broken on Id properties of SObjects? remains unfixed.

Diagnosis is made more confusing because of this hashCode() is never called when adding to Maps and Sets where the debug level determines if hashCode is called or not.

3
  • weird that it works fine when debug is finest. Is there a reason why it works with debug mode – RedDevil Jul 10 '18 at 17:59
  • 2
    Setting the debug level to FINEST uses equals to do the comparison instead of hashCode. The same Id will have different HashCodes in some cases - which causes the contains failure. This has been a bug in the platform for ~4 years now? – battery.cord Jul 10 '18 at 20:10
  • @RedDevil A guess is that the not calling hashCode was added to help isolate problems in bad hashCode implementations. But as it is not documented it does more harm than good IMHO. – Keith C Jul 10 '18 at 20:13
8

Sounds like it may be an edge case; it returns true in my org:

09:28:48.2 (4756791)|SYSTEM_METHOD_ENTRY|[7]|System.debug(ANY)
09:28:48.2 (4767250)|USER_DEBUG|[7]|DEBUG|true
09:28:48.2 (4775541)|SYSTEM_METHOD_EXIT|[7]|System.debug(ANY)

Please consider submitting a bug if you have a valid reproduction that support can use. In the general case, you should be able to use contains as intended.

8
  • Can you confirm if it was same code you tried? I tried this on Sandbox S18 , My companies' prod org and my personal 10 mb dev org. Same behavior. – Pranay Jaiswal Jul 10 '18 at 15:36
  • @PranayJaiswal I tried your code, literally copy-pasted from your question, and it worked in my dev org. – sfdcfox Jul 10 '18 at 15:39
  • 2
    I have raised a case now with SF support, Case number "19522568" , the only fear I have is they will close the case quoting "There is a workaround in place". Lets hope for the best. Thanks for your help. – Pranay Jaiswal Jul 10 '18 at 16:09
  • 4
    @PranayJaiswal If they dare do that, let me know. I'll DM the PM of Apex Code. – sfdcfox Jul 10 '18 at 16:26
  • 2
    @DanielBallinger I was running on the default SFDC_DeveloperConsole, which looks like it defaulted to FINEST Apex. I just changed it to None and set an assert, and the code now repros on NA3. So, in my case, was just a debugging red herring. – sfdcfox Jul 10 '18 at 22:22
5

I can repo this on na37.

List<Id> myIdList = new List<Id>();
myIdList.add('0060E000008PdMk');

Id oppId ='0060E000008PdMk';   

System.assert(oppId == myIdList[0]); // true 
System.assert(myIdList.contains(oppId)); // false - assertion failed !! 

Changing the types of the List and the variable to String causes this code to run as expected.


It looks like the HashCodes under the surface don't match up. This example casts our ids to objects, and calls HashCode on them, then compares them. They fail, despite the values being the same.

You can cause the contains to find the value by changing the debug level of "Apex Code" to FINEST. This (According to @KeithC) causes the comparison to not use HashCode and use equals instead, and results in a true value from contains.

List<Id> myIdList = new List<Id>();
// Added extra characters to ensure it wasnt something with 15/18 char ids 
myIdList.add(((Id)'0060E000008PdMkOIP'));

Id oppId = '0060E000008PdMkOIP';  

Integer oppHash = ((Object)oppId).hashCode();
Integer listHash = ((Object)myIdList[0]).hashCode();

System.assertEquals(oppHash, listHash); // !! Fails!! - hash values differ  

System.assert(oppId.equals(myIdList[0])); // true

// !! Setting debug APEXCODE to FINEST results in true 
System.assert(myIdList.contains(oppId)); // false 
6
  • I tried that on EU12, works fine, exactly like @sfdcfox – user1974566 Jul 10 '18 at 15:42
  • I've reproduced this on CS52 too – Derek F Jul 10 '18 at 15:45
  • Doesn't make sense, :/ Different implementation for different instances... – Pranay Jaiswal Jul 10 '18 at 15:45
  • Check out the comments under this answer from earlier this year : salesforce.stackexchange.com/a/203154/10382. Seems similar, may be playing a role (since the return false seems dead on with whats happening here) – battery.cord Jul 10 '18 at 15:48
  • 1
    Does turning on debug using finest fix this? No hashCode called in that case. – Keith C Jul 10 '18 at 16:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.