I have code in a task trigger handler that looks to see if the whoid is a contact, and if so, set a pointer in the Task object to a field in the contact. So the trigger does this: - loop through the tasks passed to the trigger to make a set of contact ids when the whoid is a contact - do a query to lookup the contacts and put them in a map - loop again through the tasks and when the whoid is a contact, get the contact from the map and get the field.

However on occasion when the code gets the contact from the map, it appears that a null is returned. I don't understand how this can happen - does this make sense to anyone?

    public void OnBeforeInsert(Task[] items) {

    private void SetContactInternalonActivity(List<Task> newEntries){      
      Set<Id> contactIdSet = new Set<Id>();
      for (Task t : newEntries) {
        if (TaskWhoIdIsAContact(t)) {
      if (contactIdSet.size() == 0)
      Map<Id, Contact> contacts = new Map<Id, Contact>([SELECT Id, Contact_Internal__c FROM Contact WHERE Id IN :contactIdSet]);

      for (Task t : newEntries) {
        if(TaskWhoIdIsAContact(t)) {
            ///// THE NEXT LINE OCCASIONALLY THROWS A System.NullPointerException EXCEPTION 
            t.Contact_Internal__c = contacts.get(t.WhoId).Contact_Internal__c;

    private boolean TaskWhoIdIsAContact(Task t) {
      return t.WhoId != null && (t.WhoId.getSobjectType() == Schema.Contact.SObjectType);
  • 1
    Is this running in a class with sharing? Perhaps the user read the WhoId, but not access the Contact record. – xn. Oct 26 '17 at 20:25

The contact was not queried. This can happen for several reasons. For example, contacts without accounts are private and cannot be queried by normal users unless they own the contact. Also, if the organization-wide defaults (OWD) are set to Private, and the trigger is running in a helper class "with sharing", it's also possible the user doesn't have access to query the record. Make sure you're using a helper class that uses "without sharing", or make sure you check if the map key is null before you try assigning the value.

Alternatively, you might make a map like this:

Map<Id, Id> contactToInternalContactId = new Map<Id, Id>();
for(Contact record: [SELECT Contact_Internal__c FROM Contact WHERE Id = :contactIdSet]) {
    contactToInternalContactId.put(record.Id, record.Contact_Internal__c);

Then, you can simplify your loop:

  for (Task t : newEntries) {
    t.Contact_Internal__c = contactToInternalContactId.get(t.WhoId);
| improve this answer | |
  • sfdcfox -- I think the third sentence sb ...contacts without accounts... – cropredy Oct 26 '17 at 23:55
  • Thanks for the answer. We do have a few contacts without accounts, but all the profiles have "read all" access to contacts and I logged in as a random user and searched for the name, and found the contacts without accounts and was able to view them. Also, the class does not say "With Sharing" and my experience is when the trigger calls these classes, "Without sharing" is in effect. I do like your simplified loop, though, thanks for that! – dwright01 Oct 27 '17 at 0:46
  • So - I still don't see how that code can get a null reference. It was mentioned that "the contact was not queried. This can happen for several reasons". What are other reasons that I may not have considered? – dwright01 Oct 30 '17 at 14:58

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.