function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
jkucerajkucera 

Null Object Error for Managed Package Class

1% of installers surface this error to me every time the Lead trigger in the app fires:

 

Apex script unhandled exception by user/organization: 00560000000nYMJ/00D30000000039c

Failed to invoke future method 'public static void evaluateLeads(SET:Id)'

caused by: System.NullPointerException: Attempt to de-reference a null object

(leadScoring)


External entry point

Debug Log:

 

Any ideas why the class LeadScoring would be null and the method call fails? 

 

This Lead trigger calls the class, which should exist upon install unless something went wrong:

 

trigger evaluateLeadScoringRulesLeadInsertOrUpdate on Lead (After insert, After update) {

Set<Id> leadIds=new Set<Id>();

//Needed as asynch apex does not allow passage of Sobjects, only Set's
for (Lead l:trigger.new){
leadIds.add(l.Id);
}//for

//Send that list of created or updated campaign members to the apex class for processing
system.debug('Future lead scoring method evaluateLeads already called? '+LeadScoring.leadScoringClassAlreadyCalled());
if (LeadScoring.leadScoringClassAlreadyCalled()==False){
system.debug('# Future Calls until limit hit: '+Limits.getLimitFutureCalls());
if (Limits.getLimitFutureCalls()>0){//don't call the method if the limit is reached
LeadScoring.evaluateLeads(leadIds);
}
}
}//trigger

 

Class called from the trigger that seems to be the source of the NPE:

 

public global class LeadScoring {

public static Boolean leadScoringClassAlreadyCalled=FALSE;

public static boolean leadScoringClassAlreadyCalled(){
return leadScoringClassAlreadyCalled;
}

@future //this method is called from the trigger. It's an asynch method so the trigger call has high governor limits
public static void evaluateLeads(Set<Id> leadIds){
evaluateLeads2(leadIds);
}//evaluateLeads

//this method is called from batch apex. It cannot be an asynch method as batch apex can't call @future methods
public static void evaluateLeads2(Set<Id> leadIds){
Integer i,j;
Double scoreChange;//safer to define as a double in case anyone tries to change the field's # decimals
Schema.DescribeFieldResult cmFieldDescribe;
leadScoringClassAlreadyCalled=TRUE;
...
...

 

Thanks for the help!

I have a managed package that works for 99% of installers, but 2 are returning these email errors to me:

 

 

Apex script unhandled exception by user/organization: 00560000000nYMJ/00D30000000039c

Failed to invoke future method 'public static void evaluateLeads(SET:Id)'

caused by: System.NullPointerException: Attempt to de-reference a null object

(leadScoring)


External entry point

Debug Log:

 

This trigger calls a bigger class, which should exist upon install unless something went wrong:

 

trigger evaluateLeadScoringRulesLeadInsertOrUpdate on Lead (After insert, After update) {

Set<Id> leadIds=new Set<Id>();

//Needed as asynch apex does not allow passage of Sobjects, only Set's
for (Lead l:trigger.new){
leadIds.add(l.Id);
}//for

//Send that list of created or updated campaign members to the apex class for processing
system.debug('Future lead scoring method evaluateLeads already called? '+LeadScoring.leadScoringClassAlreadyCalled());
if (LeadScoring.leadScoringClassAlreadyCalled()==False){
system.debug('# Future Calls until limit hit: '+Limits.getLimitFutureCalls());
if (Limits.getLimitFutureCalls()>0){//don't call the method if the limit is reached
LeadScoring.evaluateLeads(leadIds);
}
}
}//trigger

 

 

Class called from the trigger that seems to be the source of the NPE:

 

public global class LeadScoring {

public static Boolean leadScoringClassAlreadyCalled=FALSE;

public static boolean leadScoringClassAlreadyCalled(){
return leadScoringClassAlreadyCalled;
}

@future //this method is called from the trigger. It's an asynch method so the trigger call has high governor limits
public static void evaluateLeads(Set<Id> leadIds){
evaluateLeads2(leadIds);
}//evaluateLeads

//this method is called from batch apex. It cannot be an asynch method as batch apex can't call @future methods
public static void evaluateLeads2(Set<Id> leadIds){
Integer i,j;
Double scoreChange;//safer to define as a double in case anyone tries to change the field's # decimals
Schema.DescribeFieldResult cmFieldDescribe;
leadScoringClassAlreadyCalled=TRUE;
...
...

 

 

Could these be caused by:

 

 

  1. No apex perms for the running user?
  2. Bad package install?
  3. No @future perms for the running user?
As this is a managed package, the customer can't do much to debug either. 
WesNolte__cWesNolte__c

Hey

 

Can't see anything obviously wrong here. There is one bit that might confuse the call method though:

 

public static Boolean leadScoringClassAlreadyCalled=FALSE;

public static boolean leadScoringClassAlreadyCalled(){
return leadScoringClassAlreadyCalled;
}

I'm sure this sounds like I'm grasping at straws - and I am - but try declaring the variable as private. I've had more than one issue related to various code/object artifacts with the same name and similar levels of access. In each of these cases I've gotten red herring error messages.

 

Good luck,

Wes

jkucerajkucera

Thanks Wez!  I tried this but it fails creation of leads as the method is not visible from the trigger then. 

 

 

Alert: Salesforce.com experienced the following problem creating the lead below:

Reason: Apex trigger leadScoring.evaluateLeadScoringRulesLeadInsertOrUpdate caused an unexpected exception, contact your administrator: leadScoring.evaluateLeadScoringRulesLeadInsertOrUpdate: compiling trigger body

caused by: line 12, column 78: trigger body is invalid and failed recompilation: Method is not visible: leadScoring.LeadScoring.leadScoringClassAlreadyCalled()
    Lead Capture Page: Not available.

Record Information:

    company = Varsity Contractors

I appreciate you responding though as this is a really tricky issue to debug.

 

WesNolte__cWesNolte__c

Ah sorry, I meant that the variable should be private:

 

private static Boolean leadScoringClassAlreadyCalled=FALSE;

public static boolean leadScoringClassAlreadyCalled(){
return leadScoringClassAlreadyCalled;
}
jkucerajkucera

haha-thanks.  I'm a little slow on both reading carefully & replying timely.

 

I've made the var private and we'll see how it goes!  Tricky part is that I'll only know in a month or two if the next 200 installs have zero issues like this.

 

Thanks again for the help!

GoForceGoGoForceGo

John,

 

We are running into  "too many future calls:11" error.

 

Looking at this code, it appears that there is a bug. The getLimitsFutureCalls will always return 10 - this is the maximum number of calls that can be executed in the context.  The code should be as follows. Let me know what you think.

 

 
        if (Limits.getLimitFutureCalls()>0){//don't call the method if the limit is reached
            LeadScoring.evaluateLeads(leadIds);    
        }    

        should be changed to:

        Integer limit = Limits.getLimitFutureCalls() - Limits.getFutureCalls();
         
        if (limit > 0) {
              LeadScoring.evaluateLeads(leadIds);  
        }

            

 

 

jkucerajkucera

Good call GoForceGo - I don't receive those as errors via email, so I wasn't aware of the mistake.  I've updated both of the triggers that use the limit check.  

 

I'll have an updated package live probably tomorrow as the security review can take a day or two.

GoForceGoGoForceGo

You don't get apex exception messages? I assume you have sent the exception user for your package?

 

I am surprised no one else has reported this - I guess no one is calling future more than 10 times!

 

 

jkucerajkucera

Looks like you're the one :)  I think most folks don't have many apps that make @future calls and there probably aren't a lot of people that are writing their own code to make that many either.

GoForceGoGoForceGo

I think this will get fixed with this fix,. but it might be worth validating.

 

If someone else has a @future calls where they update leads, your trigger will get called. I suspect the getLimitsFutureCalls will return 0 and your @future won't get called. Otherwise,. people will get the "future cannot call future" error.

 

 

 

 

Ritesh AswaneyRitesh Aswaney

Hey GoForceGo, just wondering why you think the Limit.getLimitFutureCalls() > 0 is a bug

When it executes in a Batch Context, it should have a value of 0.

Also when in a Future Context, it should have a value of 0?

 

Limit.getLimitFutureCalls() - Limit.getFutureCalls() should in theory yield the same value?

 

I'm hitting a similar error in my code.

GoForceGoGoForceGo

If this code is evoked when you are not in a future/batch call, Limit.getLimitFutureCalls()  will always return 10. So if you are calling a future method based on this condition, you will eventually hit the limit - that's why it is  a clear bug.  If you call it from a future method, I am not too sure.