28

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, 2018 at 15:29
  • oppId == myIdList[0] returned true. Jul 10, 2018 at 15:32
  • 1
    Interesting that Apex using .hashCode() for contains differs from Java List that uses .equals() Jul 10, 2018 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, 2019 at 14:19
  • 1
    Guess who is back - success.salesforce.com/…
    – kurunve
    Jan 31, 2020 at 8:20

3 Answers 3

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, 2018 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? Jul 10, 2018 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, 2018 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. Jul 10, 2018 at 15:36
  • @PranayJaiswal I tried your code, literally copy-pasted from your question, and it worked in my dev org.
    – sfdcfox
    Jul 10, 2018 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. Jul 10, 2018 at 16:09
  • 4
    @PranayJaiswal If they dare do that, let me know. I'll DM the PM of Apex Code.
    – sfdcfox
    Jul 10, 2018 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, 2018 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 Jul 10, 2018 at 15:42
  • I've reproduced this on CS52 too
    – Derek F
    Jul 10, 2018 at 15:45
  • Doesn't make sense, :/ Different implementation for different instances... Jul 10, 2018 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) Jul 10, 2018 at 15:48
  • 1
    Does turning on debug using finest fix this? No hashCode called in that case.
    – Keith C
    Jul 10, 2018 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.