[SalesForce] SObjectException “SObject row was retrieved via SOQL without querying the requested field” not being thrown

Usually if apex code attempts to access an sObject field that wasn't retrieved via SOQL I get an exception like:

System.SObjectException: SObject row was retrieved via SOQL without
querying the requested field: Opportunity.Namespace_CustomField_c

This if useful, as it tells me to go back to the SOQL query that retrieved the Opportunity and add the CustomField__c field to the select.

However, I've noticed that the exception isn't always thrown. Instead the field in question is just null.

Has anyone else encountered this and have any idea why it happens?

As an example of the issue:

global with sharing class CustomController {
    public Opportunity opp {get; set;}

    global void method1(Id oppId) {
        opp = [Select o.Id, o.Type, o.IsWon, Error_Message__c 
               From Opportunity o where id =:oppId limit 1 FOR UPDATE];

        // Setting this field appears prevents any further SObjectExceptions
        // NB: This was added after the question was originally asked to highlight the issue. 
        opp.Error_Message__c = '';

        System.debug('opp.CustomField__c: ' + opp.CustomField__c);

        method2(opp);
    }

    public void method2(Opportunity opp) {
        if(opp.CustomField__c != null) {
            System.debug('DoStuff');
        }
    }
}
  1. Create an instance of a custom controller class CustomController
  2. Invoke the public method method1 on the above class that takes an Opportunity Id
  3. The public method method1 runs a SOQL query to retrieve the Opportunity and a number of fields, but not CustomField__c. The retrieved Opportunity is assigned to a public property opp on the controller.
  4. The Opportunity property opp is passed as a parameter to another method in the custom controller class. (I'm aware that this isn't necessary as the method would otherwise be able to see the value via the public property)
  5. The method method2 that received the Opportunity checks if the custom field is not null before attempting to use the value to do some other updates.

If I create an instance of the custom controller in anonymous apex and invoke the method from point 2 no SObjectException is thrown and the CustomField__c value is always null.

If I create an instance of the custom controller in anonymous apex, run the same SOQL query and pass the resulting Opportunity directly to the method in point 4 I get the expected SObjectException.

Best Answer

I cannot seem to reproduce what you've described, I get the sObject not retrieved error for Case 1 too!

The only caveat would be that since sObjects are passed by reference, hopefully there isn't a sneaky bit of assignment which is setting the value of CustomField1 somewhere in the foodchain.

If there is an assignment of value then it wouldn't throw the exception for any subsequent access. (Even though it wasn't initially retrieved as part of the soql)


As a simplified example, this will throw the SObjectException (assuming you have at least one Opportunity):

Opportunity opp = [select Id, StageName From Opportunity limit 1];
System.debug(opp.Probability);

And this will not (opp.Probablity will be null):

Opportunity opp = [select Id, StageName From Opportunity limit 1];
opp.StageName = 'foo';
System.debug(opp.Probability);
Related Topic