consider the following code :

Map<Object, Object> m = new Map<Object, Object>();
String s = 's';
m.put(IAccounts.class, s); // any type here does the trick


In sandbox #1, the debugs return :

enter image description here

In sandbox #2 and production, the debugs return :

enter image description here

The thing is, when you loop over the keyset from the map, and you try to debug key == IAccounts.class, it returns true.

I genuinely do not understand what is happening. Am I missing something ?

All my orgs are on the same version which is Winter '24 Patch 11.

This is problematic to me, because I use a Map<Object, Object> for mocking purposes, for both SObjectType and Type. The workaround would be to have one map for each, but still... I can't wrap my head around that.

I did not find any Known Issue for that.

Have you ever encounter a bug like this ?

Thanks =)

1 Answer 1


Maps and Sets have different internal implementations depending on the debugging level of your TraceFlag, if any. This is for debugging purposes. The highest, FINEST, behaves differently than the lower levels of debugging. Let's look at your code again, using execute anonymous:

class IAccounts {}
Map<Object, Object> m = new Map<Object, Object>();
String s = 's';
m.put(IAccounts.class, s); // any type here does the trick

System.debug(LoggingLevel.ERROR, m.containskey(IAccounts.class));
System.debug(LoggingLevel.ERROR, m.get(IAccounts.class));

In your Developer Console, go to Debug > Change Log Levels > Add/Change, and set Apex to "ERROR". You'll see the output true, s. Now, go back and change this to "FINEST", and repeat the experiment. You'll get false, null.

This is a known "bug" of how maps and sets work, and it won't be fixed. The different implementations at the highest level is meant to ensure that the map/set can be serialized correctly. I don't know the internals, but it causes problems for certain types of keys, like keys which decide to change their hashcode after being put into the map.

This is also why you'd observe different effects in different sandboxes, even on the same patch level. Your choice of what level to debug at is stored in each org independently, so simply changing the flags are enough to influence unit tests and debugging sessions in general.


Note that this has to do with how the implementations work. The lower levels use a combination of equals/hashCode, as described in Using Custom Types in Map Keys and Sets, but switch to a === based approach in FINEST mode.

Example code:

class iaccounts {} 
object i = iaccounts.class;
// All these assertions pass as of 59.0
Assert.areEqual(i.hashCode(), ((Object)iaccounts.class).hashCode());
Assert.isFalse(i === iaccounts.class);
Assert.isFalse(iaccounts.class === iaccounts.class);
  • First time in 12+ years of SF dev for me I hear about this bug ^^' "so simply changing the flags are enough to influence unit tests" what. the. actual. f. No wonder why other devs are salty about Salesforce. Anyway thank you for your help it did the job ! Oct 26, 2023 at 14:57
  • 2
    As as long-time lurker I can remember following post with similar things - salesforce.stackexchange.com/questions/254891/… or
    – kurunve
    Oct 26, 2023 at 15:20
  • @JulienGaïotto I was surprised that iaccounts.class !== iaccounts.class, even though their hashCode are equal and the equals method returns true. There are technically two bugs uncovered here. I wonder if the reference equality check is a known bug.
    – sfdcfox
    Oct 26, 2023 at 15:37
  • amazing - one more reason to avoid using FINEST as debug log level for tracing issues (I use INFO) - have you logged a doc feedback on this? I assume the PM knows about this.
    – cropredy
    Oct 26, 2023 at 17:22
  • @cropredy Ironically, if you need checkpoints, you have to use FINEST. But you're right, maybe I could file a doc feedback.
    – sfdcfox
    Oct 26, 2023 at 18:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .